Choosing a TUI framework
Choose the model you want to build with.
Language, state ownership, and deployment shape a project more than a row of checkmarks. Here is how five frameworks approach them.
Sources reviewed . SwiftTUI examples use 0.14.0; other entries describe the linked project documentation at review time.
Swift
SwiftTUI
A fit for apps that benefit from SwiftUI-style view composition, tracked state, and shared views across hosts.
- UI model
- Declarative views, state and observation; the runtime owns layout and redraw.
- Terminal platforms
- macOS 15+, Linux, and Windows 10 1809+ / Server 2019+. Swift 6.4 toolchain.
- Input
- Focus traversal, keyboard commands, and tap, drag, and hover gestures. Terminal mouse support is negotiated.
- Motion
- Built-in state animation, withAnimation, and phase animation. Terminal rendering remains cell-based.
- Browser
- Compile with SwiftTUIWASI and serve a static bundle with @swifttui/web. The browser runs the app.
- Native apps
- SwiftUIHost embeds views in macOS and iOS. Android arm64 is a preview with documented limitations.
Go
Bubble Tea
A fit for Go applications organized around messages, an update function, and a view of the model.
- UI model
- The Elm Architecture: a model, Update for incoming messages, and View for output. Bubble Tea handles redraw.
- Terminal platforms
- Cross-platform terminal applications; check the project’s platform-specific implementation and your target terminal.
- Input
- Keyboard and mouse messages. Bubbles supplies reusable controls; gesture behavior can be composed by the application.
- Motion
- Timed updates in the app; the companion Harmonica package supplies spring animation.
- Browser
- The linked core documentation describes a terminal renderer, not a bundled static browser host.
- Native apps
- No SwiftUI-style native embedding host is documented in the linked core sources. Integration requires additional work.
Python
Textual
A fit for Python applications with a widget tree, CSS layout and styling, and reactive properties.
- UI model
- Composed widgets, reactive attributes, events, and CSS for layout and presentation.
- Terminal platforms
- Linux, macOS, and Windows, using a supported Python environment.
- Input
- Keyboard focus, bindings, and mouse events including movement and clicks.
- Motion
- Built-in animation of numeric values, colors, and styles, with easing.
- Browser
- textual-serve runs the Python application on a server and connects a browser over WebSockets. It is not a static WASM bundle.
- Native apps
- The linked project documents terminal and browser delivery; a native app wrapper is a separate integration.
Rust
Ratatui
A fit for Rust applications that want direct control over rendering, state management, and event handling.
- UI model
- Immediate-mode rendering with widgets and constraint-based layout. The application chooses its state and event architecture.
- Terminal platforms
- Platform support depends on the chosen terminal backend; Crossterm is the common cross-platform choice.
- Input
- Events come from the backend or an input library. The app routes them to its state and controls.
- Motion
- Application-driven frame updates; the companion tachyonfx crate provides effects and animation.
- Browser
- The separate Ratzilla project provides web backends for Rust/WASM applications built with Ratatui.
- Native apps
- Alternate backends and embedding are possible; native integration is not the same contract as SwiftUIHost.
JavaScript / TypeScript
Ink
A fit for command-line tools that use React components, hooks, and the Node.js ecosystem.
- UI model
- A React renderer for terminal output, with Yoga-based flexbox layout.
- Terminal platforms
- Runs in Node.js. Verify the supported Node version and terminal behavior for your deployment targets.
- Input
- Keyboard input and focus hooks. Mouse gestures are not presented as a core API in the linked documentation.
- Motion
- useAnimation provides a shared timer, frame count, elapsed time, and delta. The application defines interpolation or frame content.
- Browser
- React familiarity does not make the Ink renderer a browser renderer; no static browser host is documented in the core README.
- Native apps
- Ink targets terminal output. React Native is a different renderer and is not an Ink embedding host.
Reading the comparison
Built-in, companion, and custom are different choices.
A companion package can be the right tool. A capability not documented in the linked core sources may still be available elsewhere in its ecosystem.
Browser hosting also has different meanings: serving a process over a connection and running a static WebAssembly bundle have different deployment requirements. Platform support does not imply identical behavior in every terminal. Check the linked requirements against your application.