textual-rs 0.3.10

A Rust port of the Textual TUI framework — build beautiful terminal UIs with CSS styling, reactive signals, and composable widgets
Documentation

textual-rs

A Rust TUI framework inspired by Python Textual, delivering modern terminal interfaces with CSS styling, reactive state, and rich widgets.

Features

Widgets (28+)

Widget Description
Button Clickable with 3D depth, press animation
Input Single-line text field with clipboard (Ctrl+C/V), text selection, validation states
TextArea Multi-line editor with selection, clipboard, scroll
Checkbox Toggle with checked/unchecked/indeterminate states
Switch Animated pill-shaped sliding toggle
RadioButton / RadioSet Mutually exclusive option groups
Select Dropdown overlay with search filtering
ListView Scrollable item list with keyboard navigation
DataTable Columns, zebra striping, sortable headers, cursor row
Tree / TreeView Hierarchical collapsible nodes
Tabs / TabbedContent Tab bar with animated underline indicator
Markdown Rendered markdown with headings, lists, code blocks
Log Scrollable append-only message log
ProgressBar Determinate progress with half-block fill
Sparkline Braille-character mini charts
Collapsible Expandable/collapsible sections
Placeholder Quadrant cross-hatch placeholder
ScrollView Scrollable container with eighth-block scrollbar
Header / Footer App chrome with key badges
Horizontal / Vertical Layout containers
ContextMenu Right-click floating overlay menus
CommandPalette Ctrl+P command discovery overlay
Label Static text display
RichLog Scrollable rich-text log with styled lines
LoadingIndicator Animated spinner overlay on any widget
Toast Stacked transient notifications with severity levels

Styling

  • CSS/TCSS engine -- type, class, and ID selectors with cascade and specificity
  • Theme variables -- $primary, $surface, $accent, with shade generation ($primary-lighten-2, $accent-darken-1)
  • 7 built-in themes -- textual-dark, textual-light, tokyo-night, nord, gruvbox, dracula, catppuccin
  • Runtime theme switching -- Ctrl+T to cycle themes
  • 8 border styles -- ascii, blank, double, heavy, inner, outer, round, tall (McGugan Box)
  • Box model -- padding, margin, min/max width/height, flex grow
  • Pseudo-classes -- :focus, :hover with automatic visual feedback
  • Custom themes -- override any variable via user CSS

Layout

  • Flexbox via Taffy -- layout-direction: vertical | horizontal, flex-grow, align-items, justify-content
  • Dock -- dock: top | bottom | left | right for fixed chrome
  • Responsive -- recomputes on terminal resize

Interaction

  • Mouse -- click, hover tracking, scroll wheel, right-click context menus
  • Mouse capture stack -- push/pop mouse-enabled state; Shift+click bypasses capture for native text selection
  • Keyboard -- key bindings, Tab/Shift+Tab focus cycling, Ctrl+C/X/V clipboard
  • Focus system -- visible focus indicators with border color changes

Reactive State

  • Reactive<T> -- property wrapper that triggers re-renders on change
  • Signals -- built on reactive_graph (from Leptos); ArcRwSignal / ArcMemo
  • Message passing -- typed async messages bubble up the widget tree

Background Work

  • Worker API -- run_worker() and run_worker_with_progress() for async tasks off the UI thread
  • Command palette -- register commands via CommandRegistry, invoke with Ctrl+P

Animation

  • Tween system -- easing functions (linear, ease-in-out-cubic, ease-out-cubic)
  • Built-in animations -- Switch toggle slide, Tab underline slide
  • 30fps render tick -- ratatui diff makes unchanged frames nearly free

Rendering

  • Sub-cell graphics -- half-block, eighth-block, quadrant, and braille characters
  • McGugan Box borders -- thin tall borders using Unicode block elements
  • Terminal capability detection -- color depth, Unicode support auto-detected

Testing

  • TestApp -- headless application harness, no terminal needed
  • Pilot -- simulated keyboard/mouse input for integration tests
  • Snapshot testing -- insta-based plain-text buffer snapshots
  • 21 visual regression tests included

Cross-platform

  • Windows 10+, macOS, Linux
  • ratatui 0.30 + crossterm 0.29 backend
  • Stable Rust (no nightly required), MSRV 1.88

Quick Start

cargo add textual-rs

Or add manually to Cargo.toml:

[dependencies]
textual-rs = "0.3"
use textual_rs::{App, Widget, Label, Button, Header, Footer};
use textual_rs::widget::context::AppContext;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;

struct MyScreen;

impl Widget for MyScreen {
    fn widget_type_name(&self) -> &'static str { "MyScreen" }
    fn compose(&self) -> Vec<Box<dyn Widget>> {
        vec![
            Box::new(Header::new("My App")),
            Box::new(Label::new("Hello, textual-rs!")),
            Box::new(Button::new("Click Me")),
            Box::new(Footer),
        ]
    }
    fn render(&self, _ctx: &AppContext, _area: Rect, _buf: &mut Buffer) {}
}

fn main() -> anyhow::Result<()> {
    let mut app = App::new(|| Box::new(MyScreen))
        .with_css("MyScreen { layout-direction: vertical; background: $background; color: $foreground; }");
    app.run()
}

Styling with CSS

Screen {
    background: $background;
    color: $foreground;
}

Button {
    border: inner;
    min-width: 16;
    height: 3;
    background: $surface;
    color: $foreground;
}

Button.primary {
    background: $primary;
    color: #ffffff;
}

*:focus {
    border: tall $accent;
}

Examples

cargo run --example demo                  # Widget showcase (4 tabs)
cargo run --example irc_demo              # IRC client demo
cargo run --example tutorial_01_hello     # Hello world
cargo run --example tutorial_02_layout    # Layout system
cargo run --example tutorial_03_events    # Event handling
cargo run --example tutorial_04_reactive  # Reactive state
cargo run --example tutorial_05_workers   # Background workers

Documentation

License

MIT