SuperLightTUI
Superfast to write. Superlight to run.
Crate · Docs · Examples · Contributing
Showcase
Getting Started
5 lines. No App struct. No Model/Update/View. No event loop. Ctrl+C just works.
A Real App
use ;
State lives in your closure. Layout is row() and col(). Styling chains. That's it.
Why SLT
Your closure IS the app — No framework state. No message passing. No trait implementations. You write a function, SLT calls it every frame.
Everything auto-wires — Focus cycles with Tab. Scroll works with mouse wheel. Containers report clicks and hovers. Widgets consume their own events.
Layout like CSS, syntax like Tailwind — Flexbox with row(), col(), grow(), gap(), spacer(). Tailwind shorthand: .p(), .px(), .py(), .m(), .mx(), .my(), .w(), .h(), .min_w(), .max_w().
ui.container
.border
.p.mx.grow.max_w
.col;
Two dependencies — crossterm for terminal I/O. unicode-width for character measurement. That's the entire dependency tree.
Widgets
14 built-in widgets, zero boilerplate:
ui.text_input; // single-line input
ui.textarea; // multi-line editor
if ui.button // button returns bool
ui.checkbox; // toggle checkbox
ui.toggle; // on/off switch
ui.tabs; // tab navigation
ui.list; // selectable list
ui.table; // data table
ui.spinner; // loading animation
ui.progress; // progress bar
ui.scrollable.col; // scroll container
ui.toast; // notifications
ui.separator; // horizontal line
ui.help; // key hints
Every widget handles its own keyboard events, focus state, and mouse interaction.
Custom Widgets
Implement the Widget trait to build your own:
use ;
// Usage: ui.widget(&mut rating);
Focus, events, theming, layout — all accessible through Context. One trait, one method.
Features
| Feature | API |
|---|---|
| Vertical stack | ui.col(|ui| { }) |
| Horizontal stack | ui.row(|ui| { }) |
| Gap between children | .gap(1) |
| Flex grow | .grow(1) |
| Push to end | ui.spacer() |
| Alignment | .align(Align::Center) |
| Padding | .p(1), .px(2), .py(1) |
| Margin | .m(1), .mx(2), .my(1) |
| Fixed size | .w(20), .h(10) |
| Constraints | .min_w(10), .max_w(60) |
| Text wrapping | ui.text_wrap("long text...") |
| Borders with titles | .border(Border::Rounded).title("Panel") |
ui.text.bold.italic.underline.fg.bg;
16 named colors · 256-color palette · 24-bit RGB · 6 modifiers · 4 border styles
run_with;
Dark and light presets. Custom themes with 13 color slots. All widgets inherit automatically.
- Double-buffer diff — only changed cells hit the terminal
- u32 coordinates — no overflow on large terminals
- Clipping — content outside container bounds is hidden
- Resize handling — automatic reflow on terminal resize
let mut tween = new.easing;
let value = tween.value;
let mut spring = new;
spring.set_target;
Tween with 9 easing functions. Spring with configurable stiffness and damping.
run_inline;
Render a fixed-height UI below the cursor without taking over the terminal.
let tx = run_async?;
tx.send.await?;
Optional tokio integration. Enable with cargo add superlighttui --features async.
Press F12 in any SLT app to toggle the layout debugger overlay. Shows container bounds, nesting depth, and layout structure.
Examples
| Example | Command | What it shows |
|---|---|---|
| hello | cargo run --example hello |
Minimal setup |
| counter | cargo run --example counter |
State + keyboard |
| demo | cargo run --example demo |
All 14 widgets |
| demo_dashboard | cargo run --example demo_dashboard |
Live dashboard |
| demo_cli | cargo run --example demo_cli |
CLI tool layout |
| demo_spreadsheet | cargo run --example demo_spreadsheet |
Data grid |
| demo_website | cargo run --example demo_website |
Website in terminal |
| demo_tetris | cargo run --example demo_tetris |
Playable Tetris |
| inline | cargo run --example inline |
Inline mode |
| anim | cargo run --example anim |
Tween + Spring |
| async_demo | cargo run --example async_demo --features async |
Background tasks |
Architecture
Closure → Context collects Commands → build_tree() → flexbox layout → diff buffer → flush
Each frame: your closure runs, SLT collects what you described, computes flexbox layout, diffs against the previous frame, and flushes only the changed cells.
~5,800 lines of Rust. 11 source files. No macros, no code generation, no build scripts.
Contributing
See CONTRIBUTING.md for guidelines.