Thanks to visit codestin.com
Credit goes to github.com

Skip to content

IllusiveBagel/Rustact

Rustact logo

CI Latest Release Crates.io

Rustact is a React-inspired, async terminal UI framework built on top of ratatui, crossterm, and tokio. Components render into a virtual tree, hooks manage state, side effects, and context, and the runtime diff-patches frames to keep redraws quick even when ticks fire continuously.

Install from crates.io:

cargo add rustact

Quick start

Build a minimal app

use rustact::{component, App, Element, Scope};
use rustact::{is_button_click, ButtonNode};

fn counter(ctx: &mut Scope) -> Element {
    let (count, set_count) = ctx.use_state(|| 0i32);

    ctx.use_effect((), move |dispatcher| {
        let mut events = dispatcher.events().subscribe();
        let handle = tokio::spawn(async move {
            while let Ok(event) = events.recv().await {
                if is_button_click(&event, "counter:inc") {
                    set_count.update(|value| *value += 1);
                }
            }
        });
        Some(Box::new(move || handle.abort()))
    });

    Element::vstack(vec![
        Element::text(format!("Count: {count}")),
        Element::button(ButtonNode::new("counter:inc", "+").filled(true)),
    ])
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let root = component("Counter", counter);
    App::new("counter-demo", root)
        .watch_stylesheet("styles/app.css")
        .run()
        .await
}

Run the kitchen-sink demo

cd examples/rustact-demo
RUSTACT_WATCH_STYLES=1 cargo run
  • Counter, gauges, tables, trees, forms, toasts, and tips live in one app under examples/rustact-demo/src/main.rs.
  • Set RUSTACT_WATCH_STYLES to 1, true, or on to hot-reload styles/demo.css while the example is running.

Ops dashboard showcase

cd examples/ops-dashboard
cargo run

Explore layered overlays (LayeredNode), toasts (ToastStackNode), tabs, and modal dialogs, all powered by hooks and shared context.

Scaffold a new project

cargo install cargo-generate
cargo generate \
  --git https://github.com/IllusiveBagel/rustact \
  --branch main \
  --path templates/rustact-app \
  --name my-rustact-app
cd my-rustact-app
cargo run

The template mirrors the demo’s structure (components, dispatcher usage, stylesheet, README) so you can immediately iterate on your own TUI.

Why Rustact?

  • Component + hook model – Declare components with component("Name", handler) and manage state via use_state, use_reducer, use_ref, use_memo, use_callback, use_effect, provide_context, use_context, and the dedicated use_text_input / use_text_input_validation hooks.
  • Async runtime + event bustokio drives terminal IO, ticks, shutdown, and external signals; subscribe to FrameworkEvents through Dispatcher::events() for keyboard, mouse, resize, and timer events.
  • Injectable drivers & headless mode – Use App::with_driver to plug deterministic drivers for tests or simulations, or call App::headless() to render without a terminal for snapshots.
  • Rich widget setElement builders cover flex layouts, blocks, lists, tables, trees, forms, gauges, buttons, inputs, tabs, layered overlays, modals, and toast stacks.
  • Text input system – Handles focus rings, cursor placement, secure mode, validation state, and shared registries so inputs behave like native controls (including mouse hits and Tab cycling).
  • CSS-inspired styling – The Stylesheet parser understands :root, element/id/class selectors, and custom properties so you can recolor UI, resize columns, rename labels, or toggle fills without recompiling.
  • Hot-reloadable themesApp::watch_stylesheet plus the RUSTACT_WATCH_STYLES env var reload styles whenever styles/demo.css (or any configured path) changes.
  • View diffing + tracing – Frames are diffed before drawing, and every render/event/shutdown emits tracing spans so you can profile and debug behavior.

Styling workflow

Rustact looks for a sibling stylesheet (for the demos that is styles/demo.css). You can define palette tokens in :root, override widget-specific properties, and reload on every save.

:root {
    --accent-color: #5af78e;
    --warning-color: #ffb86c;
}

button#counter-plus {
    accent-color: var(--accent-color);
    --filled: true;
}

input.feedback-name {
    border-color: #8be9fd;
    placeholder: "Display name";
}

Run any example with RUSTACT_WATCH_STYLES=1 cargo run to live-reload the stylesheet. For custom apps, chain .watch_stylesheet("styles/app.css") on App and keep the env var enabled while iterating.

Read website/content/docs/styling.md for the full selector/property reference and integration tips.

Documentation & resources

Repository layout

  • src/ – core runtime, renderer, hooks, context, styles, text input system, and integration tests.
  • examples/ – standalone apps (rustact-demo, ops-dashboard) that depend on the local crate via path dependencies.
  • templates/ – reusable scaffolds; currently templates/rustact-app.
  • website/ – documentation source consumed by GitHub Pages.
  • CHANGELOG.md, RELEASE.md, MAINTAINERS.md, CONTRIBUTING.md – project process, release, and ownership docs.

Community & contributions

License

Rustact is distributed under the MIT License. By contributing, you agree that your contributions will be licensed under the same terms.

About

Rustact is a React-inspired framework for building async terminal UIs in Rust.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Contributors