Skip to content

TUI Framework Comparison

A feature comparison of major terminal UI frameworks across languages and ecosystems. Covers rendering, terminal protocols, layout, components, developer experience, and architecture. Values reflect the state of each framework as of 2026-03.

For an in-depth Silvery vs Ink analysis with code examples, benchmarks, and migration guidance, see silvery-vs-ink.md.

Legend: ✅ Full support (built-in, documented) | ⚡ Best-in-class | 🔶 Partial support | ❌ Not supported | 🔧 Community/plugin

Ratings reflect the author's assessment based on documented features, benchmarks, and public APIs. ⚡ indicates category-leading implementation, not just presence of a feature.

Rendering

FeatureSilveryInkBubbleTeaTextualNotcursesFTXUIblessed
Incremental rendering (dirty tracking)⚡ Per-node dirty flags [^1]❌ Full repaint❌ Full repaint✅ Dirty widgets⚡ Damage map per ncplane❌ Full repaint🔶 Manual
Style transition cache (minimal SGR diff)⚡ Interned styles + cached SGR transitions [^2]🔶
Damage rectangles / dirty regions⚡ Row-level bounding box + bitset✅ Per-widget regions⚡ Per-plane damage
Double buffering✅ Packed Uint32Array cells❌ String-based✅ ncplanes🔶
Synchronized output (DEC 2026)✅ Automatic❌ [^3]✅ v2 alpha
Wide character support (CJK)⚡ Built-in wcwidth + grapheme splitting + atomic diff🔶 Third-party string-width⚡ Built-in wcwidth🔶
Frame rate limiting✅ Scheduler coalescing🔶 Manual tick✅ Configurable FPS

[^1]: Silvery tracks 7 independent dirty flags per node (contentDirty, layoutDirty, paintDirty, subtreeDirty, childrenDirty, childPositionChanged, hasPrevBuffer), enabling style-only changes to skip layout and content changes to skip paint.

[^2]: With ~15-50 unique styles per TUI, Silvery caches all (oldStyle, newStyle) SGR transition strings (~2,500 possible pairs), eliminating per-cell string building.

[^3]: Ink has a PR exploring synchronized updates (#846) but it is not yet merged (as of 2026-03).

Terminal Protocols

FeatureSilveryInkBubbleTeaTextualNotcursesFTXUIblessed
Kitty keyboard protocol⚡ Full spec: all 5 flags, auto-detect [^4]❌ [^5]🔶 v2 alpha
Bracketed paste modeusePaste hook, auto-enable✅ Default since v0.26🔶
OSC 52 clipboard✅ Copy + query, works over SSH🔶 v2 alpha via terminfo Ms
OSC 8 hyperlinks<Link> component
OSC 9/99 notifications✅ Auto-detect (iTerm2/Kitty)notify()
SGR mouse events✅ Click, drag, wheel, modifiers🔶 Basic via useInput
Sixel images✅ Auto-detect with fallback🔧 x/cellbuf
Kitty graphics protocol✅ Auto-detect with fallback🔧 x/cellbuf
Alternate screen

[^4]: Silvery supports all Kitty flags: DISAMBIGUATE, REPORT_EVENTS (press/repeat/release), REPORT_ALTERNATE, REPORT_ALL_KEYS, REPORT_TEXT. Detects Cmd/Super and Hyper modifiers, CapsLock/NumLock. Auto-detects terminal support via CSI ? u query.

[^5]: Ink has a PR (#852) for Kitty keyboard support in review but not merged (as of 2026-03).

Layout & Components

FeatureSilveryInkBubbleTeaTextualNotcursesFTXUIblessed
Layout engine⚡ Flexbox (Flexily 7KB pure JS or Yoga) [^6]Flexbox (Yoga WASM)Manual⚡ CSS subset (grid + flexbox)Manual ncplane stackingFlexbox-like (C++)Manual
React/component model⚡ React 19, JSX, hooks✅ React 19, JSX, hooks⚡ Elm architecture (Model-Update-View)Widget classesC structsC++ componentsEvent emitter objects
Layout feedback (components know their size)useContentRect() / useScreenRect() — synchronous [^7]🔶 useBoxMetrics() post-layoutsize property on widgets🔶 ncplane dimensions🔶🔶
Virtual list / lazy renderingVirtualList component🔧 list Bubble✅ Built-in ListViewList
Text input components✅ TextInput (with readline), TextArea (multi-line)🔧 ink-text-input🔧 textinput BubbleInput, TextAreaInputTextbox, Textarea
Focus management⚡ Tree-based: scopes, spatial nav, autoFocus, click-to-focus🔶 Tab-order focus (useFocus)🔶
Scroll containersoverflow="scroll" with auto-measurement❌ Open since 2019 (#222)🔧 viewport BubbleScrollableContainer✅ ncplane scrolling
Theming / CSS✅ ThemeProvider + semantic tokens🔶 Style props⚡ CSS files + live reload🔶🔶

[^6]: Silvery's Flexily layout engine is pure JavaScript (7 KB gzipped) with zero native dependencies. It matches Yoga WASM performance. Layout results are cached via fingerprinting, so unchanged subtrees skip recomputation entirely.

[^7]: Silvery's two-phase rendering runs layout before components render, so useContentRect() returns actual dimensions synchronously during render, not via a post-render callback. This eliminates an entire category of bugs around "width is 0 on first render."

Developer Experience

FeatureSilveryInkBubbleTeaTextualNotcursesFTXUIblessed
Testing utilities (headless render)⚡ Playwright-style locators, auto-refreshing [^8]ink-testing-library🔧 teatest✅ Pilot (async testing)
Hot reload🔶 Via Bun/Node watch mode🔶 Via bundler✅ CSS hot reload
DevTools / inspector🔶 withDiagnostics invariant checker🔶 React DevTools⚡ Web-based DevTools (DOM mirror)
Plugin compositionwithCommands / withKeybindings / withDiagnostics🔶 Middleware via tea.Cmd
Driver pattern (AI/test automation)⚡ Command introspection + state query + screenshot [^9]
TypeScript support⚡ Native, strict mode❌ (Go)❌ (Python, typed)❌ (C)❌ (C++)🔶 @types/blessed
Screenshots (buffer to image)bufferToHTML() + Playwright✅ SVG export

[^8]: Silvery's createRenderer provides auto-refreshing locators (same locator object always queries fresh tree state), getByTestId/getByText/CSS attribute selectors, bounding box assertions, and Playwright-style press() input. Locators never go stale.

[^9]: The driver pattern composes withCommands + withKeybindings + withDiagnostics to expose all commands as callable functions with metadata (ID, name, help, keybindings). An AI agent can list available commands, inspect screen state, execute actions, and capture screenshots -- all programmatically.

Architecture

FeatureSilveryInkBubbleTeaTextualNotcursesFTXUIblessed
Rendering modelRetained (React tree + dirty tracking)Retained (React tree, line-based diff)Immediate (Model-Update-View)Retained (widget tree)Retained (ncplane stack)ImmediateRetained (widget tree)
State managementReact hooks or Zustand storeReact hooksElm-style (Model + Update + Cmd)Reactive attributes + message passingManualComponent stateEvent emitter
Input handlingInputLayer stack (DOM-style bubbling) + command systemuseInput (flat, no isolation)Update(msg)Message dispatch + bindingsDirect ncplane inputEvent handlerEvent emitter
Language / runtimeTypeScript / Bun or Node.jsJavaScript / Node.jsGoPython (3.8+)C (C99)C++ (17)JavaScript / Node.js
Native dependenciesNone (pure JS/TS)Yoga WASM (binary blob)NoneNoneterminfo, FFI libsNoneNone
Memory in long sessionsConstant (normal JS GC)Grows (Yoga WASM linear memory) [^10]ConstantConstantConstantConstantGrows (known leaks)
Render targetsTerminal, Canvas 2D, DOM (experimental)Terminal onlyTerminal onlyTerminal + Web (Textual-web)Terminal onlyTerminal onlyTerminal only
Community / ecosystemNew (active development)Mature (~1.3M npm weekly, 50+ components)Large (Go ecosystem, 100+ Bubbles)Growing (Python ecosystem)Niche (C specialists)Moderate (C++ community)Legacy (unmaintained)
Maintenance statusActiveActiveActiveActiveSlow / winding downActiveUnmaintained

[^10]: Ink uses Yoga WASM, whose linear memory grows monotonically and cannot shrink without a module reset. This has caused 120+ GB memory usage in long-running production apps (e.g., Claude Code).

Unique Strengths

Performance claims below are summary figures. Reproduce with bun run bench for full benchmark data.

Silvery

  • Two-phase rendering with responsive layout: Components know their dimensions during render via useContentRect() -- the only React-based TUI framework where this works synchronously.
  • Per-node dirty tracking: Interactive updates (keystroke, scroll) skip unchanged nodes entirely, avoiding full re-renders. See detailed benchmarks for comparison data.
  • Driver pattern for AI automation: Composable plugins (withCommands + withKeybindings + withDiagnostics) expose the full command surface for programmatic control, introspection, and testing.

Ink

  • Largest ecosystem: ~1.3M npm weekly downloads, 50+ community components (prompts, spinners, tables, select inputs), used by Gatsby, Prisma, Terraform CDK, Shopify CLI.
  • Familiar React model: Lowest learning curve for React developers -- standard hooks, JSX, and component patterns.
  • Battle-tested stability: 8+ years of production use across thousands of CLI tools.

BubbleTea

  • Elm architecture in Go: Clean Model-Update-View pattern with immutable state. Easy to reason about, easy to test.
  • Rich component ecosystem: 100+ community "Bubbles" (tables, file pickers, progress bars, viewports, markdown renderers).
  • Single binary deployment: Go compiles to a static binary -- no runtime dependencies, no package manager.

Textual

  • CSS theming: Full CSS files with selectors, variables, and live reload. The closest any TUI framework gets to web-style styling.
  • Web-based DevTools: A DOM mirror inspector running in the browser, with widget tree exploration, CSS debugging, and live editing.
  • Textual-web: Serve any Textual app as a web application with no code changes.

Notcurses

  • Best image rendering: Native Sixel and Kitty graphics protocol support with per-pixel rendering. The gold standard for terminal graphics.
  • ncplane compositing: Layered rendering planes with independent z-ordering, scrolling, and damage tracking. Arbitrary overlapping regions without manual clipping.
  • Performance ceiling: C implementation with zero-copy rendering paths. Handles the highest throughput workloads (media players, data visualizers).

FTXUI

  • Zero dependencies: Pure C++17 with no external libraries. Single header inclusion for simple projects.
  • Immediate mode simplicity: UI is a pure function of state -- no retained tree, no lifecycle management, no stale state bugs.
  • Cross-platform C++: Works on Linux, macOS, Windows, and WebAssembly (Emscripten) from the same codebase.

blessed (legacy)

  • Historical significance: The original comprehensive Node.js TUI framework (2013). Inspired Ink's creation and influenced the terminal UI ecosystem.
  • Widget completeness: The most complete built-in widget set of any Node.js TUI library (lists, forms, tables, file managers, terminals-in-terminals). No other Node.js framework matched its breadth.
  • Note: Unmaintained since ~2017. neo-blessed is a community fork with minor fixes but no active development. Listed here for historical context.

Released under the MIT License.