Build Swift Terminal User Interfaces

Views, State, Observation, Gestures, Animations—

SwiftUI semantics, drawn in terminal cells.

Read the API reference
SourceCounterApp.swift
Open file
public import SwiftTUIRuntime

struct CounterView: View {

  @Environment(\.terminalSize) private var terminalSize
  @State private var count = 0
  @State private var activeRippleID: Int? = nil

  var body: some View {
    VStack(spacing: 1) {
      TextFigure("\(count)", font: .future)
        .frame(minWidth: 14, alignment: .center)
      Button("Increment") {
        count += 1
      }
    }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    .onChange(of: count) {
      if activeRippleID == nil {
        activeRippleID = count
      }
    }
    .background {
      if let rippleID = activeRippleID {
        RippleLayer(reach: reach) {
          if activeRippleID == rippleID {
            activeRippleID = nil
          }
        }
        .id(rippleID)
      }
    }
  }

  private var reach: Double {
    let horizontal = Double(terminalSize.width) / 2
    let vertical = Double(terminalSize.height)
    return (horizontal * horizontal + vertical * vertical).squareRoot()
  }
}
SwiftTUI appCompiled for browser with SwiftTUIWASI
Open separately

Run the exact source shown beside this frame.

Real SwiftTUI viewStatic WASI bundleCanvas with one-way semantic accessibility tree

Run this same counter in the terminal, SwiftUI, or a browser.

Clone the counter

Get started

A terminal and a toolchain. That's it.

SwiftTUI apps are plain SwiftPM packages: any Swift 6.3+ toolchain builds and runs them from the command line, on macOS, Linux, or Windows. You do not need an Xcode project, a simulator, or an app store. If you already run a current Xcode, its bundled toolchain is all you need.

Run the counterswift-tui-counter-demo
Open repo
# macOS, Linux, or Windows — any Swift 6.3+ toolchain
git clone https://github.com/SwiftTUI/swift-tui-counter-demo.git
cd swift-tui-counter-demo
swift run --package-path counter counter

The same counter as the live demo above, drawn in your own terminal. Space increments; Ctrl-C quits.

Pick a toolchain

swiftly, Swift's official toolchain installer for macOS and Linux, puts swift on your path in one step, without Xcode. On a Mac with a current Xcode, skip it: the toolchain is already installed. On Windows, use the swift.org installer instead.

Add it to your app

// Package.swift
.package(
  url: "https://github.com/SwiftTUI/swift-tui",
  .upToNextMinor(from: "0.9.6")
),
// in your executable target:
.product(name: "SwiftTUI", package: "swift-tui")
Read the documentation

Why SwiftTUI

A proven UI model, pointed at the terminal.

Most TUI toolkits make you choose between a low-level draw loop and a widget set with its own ad-hoc state story. SwiftTUI instead borrows the declarative model SwiftUI has proven at platform scale (the interface is a function of state) and aims it at terminal cells. You declare views; the framework owns layout, focus, redraw, and the terminal itself.

  1. 01

    State in, screen out

    There is no draw loop, no buffer diffing, and no repaint bookkeeping. Views are a pure function of your app's state: change a value and the runtime recomputes layout and rewrites exactly the cells that changed. SwiftUI has spent seven years hardening that model in production; here it is the entire programming model.

    View · @State · @Observable · body
  2. 02

    Real components, real focus

    Buttons, text fields, pickers, sliders, scroll views, and charts, with a focus engine, tab traversal, keyboard chords, tap · drag · hover gestures, and animation built in. You compose behavior instead of hand-routing key events to widgets.

    @FocusState · TapGesture · withAnimation · SwiftTUICharts
  3. 03

    The terminal, negotiated for you

    Truecolor, Kitty and Sixel images, OSC 8 hyperlinks, and mouse reporting are probed per session and degrade gracefully: one binary is correct in kitty, a bare SSH session, or CI. You write views, never escape codes.

    TerminalCapabilityProfile · Kitty · Sixel · OSC 8
  4. 04

    One compiled binary

    Swift 6 compiles your interface into a single fast executable with checked concurrency. Layout and state are type-checked at build time, and tests render frames as integer-cell rasters without a TTY.

    SwiftPM · Swift 6 · RasterSurface

How it compares

Capability axes against the other major TUI frameworks. The first three are the day-one terminal experience; the last three are where the same source can travel later.

frameworkTerminal renderingDeclarative UIPointer & gesturesNative app embedServed to browserStatic WASM build
SwiftTUI✓ SwiftUI-shaped✓ tap·drag·hover✓ SwiftUIHost · Android arm64 preview✓ WebHost · DOM✓ WASI · DOM
Bubble Tea (Go)✓ Elm arch~ mouse events
Textual (Python)✓ widgets · CSS~ mouse · hover✓ serve · xterm
Ratatui (Rust)— immediate-mode~ backend only~ Ratzilla · DOM
Ink (JS/React)✓ React

Verified August 2026 against current releases: Bubble Tea 2.0 · Textual 8.2 · Ratatui 0.30 · Ink 7.1.  first-party · ~ partial, separate package, or raw mouse events ·  none. Ratzilla is a separate crate in the Ratatui org; Textual's browser host streams a server-side process through xterm.js. SwiftTUI's browser paths render to the DOM with a real accessibility tree for one-way semantic presentation; assistive-origin control actions are not part of the 0.9 preview.

Terminal first: when you need it, the same views also run in the browser, in native macOS and iOS windows, and in an Android arm64 preview. Android packaging is limited to arm64-v8a, API 28+, and NDK 27.3.13750724 through the AAR/Gradle-plugin path. Full IME marked/pre-edit composition is incomplete and semantics are one-way; a connected journey exists, but current candidate device acceptance remains pending. Start with the hosts & platforms guide, or go straight to swift-tui-web, swift-tui-swiftui, or swift-tui-android.

Showcase

Built with SwiftTUI.

The counter above fits on one screen. These do not. Both are maintained examples in swift-tui-examples: clone the repo and every example builds and runs with one command.

Browse every example and host