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()
}
}
Build Swift Terminal User Interfaces
Views, State, Observation, Gestures, Animations—
SwiftUI semantics, drawn in terminal cells.
Read the API referenceRun the exact source shown beside this frame.
Starting the WASI runtime
The source and static site remain available.
Run this same counter in the terminal, SwiftUI, or a browser.
Clone the counterGet 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.
# 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 counterThe 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 documentationWhy 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.
- 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 - 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 - 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 - 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.
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.


Further reading
Community
Build with us.
Development happens in public on GitHub, and the people building SwiftTUI are on Discord. Come ask questions, show what you are building, or talk through a contribution.