Skip to main content

Crate ratcn

Crate ratcn 

Source
Expand description

Themeable terminal UI components for ratatui, plus the runtime that makes them interactive.

Ratatui gives you widgets that draw. ratcn adds the parts a real app needs on top: components that can be focused, hovered, and clicked, in a shadcn-inspired visual style you can theme.

§Preview status

This is a preview release.

  • The API will break. The public surface is still moving: recent work has renamed methods, changed signatures, and removed components. Pin an exact version and expect to edit when you upgrade.
  • There is no install command. Each component module is self-contained and meant to be copied into your own project, but copying is a manual file copy today. A CLI is intended and does not exist.
  • The component set is small and growing. Eight ship today: Button, List, Select, Tabs, Dialog, Toaster, BarChartWidget, and Tooltip. Text input, a multi-line text area, and a scroll area are planned next; there is no text entry component at all right now.

§Up to two halves, usable alone

Components have up to two cooperating halves:

ToasterWidget is paint-only and stops at the widget half. BarChartWidget is paint-only too, but it is also not a component in the sense used above: it is a themed adapter over ratatui’s own BarChart, adding theme colors, grouping, and a value-display switch to a chart ratatui draws. Dialog is the opposite exception: it is an interactive composite with no separate paint widget.

The paint widgets drop straight into a plain ratatui app. They take a theme and some bools, and frame.render_widget(...) is the whole integration — no Ratcn, no declaration pass, no message type. If you already have focus and event handling you are happy with, take the components’ look and leave the runtime alone. Where both halves exist, the interactive half paints through the same widget.

§It does not take over your app

This is a toolkit, not a framework. Your app keeps its event loop, its state, and its update function. The runtime enters at exactly two call sites, and both can be removed again:

State stays yours throughout. Components read it and return messages asking for changes; nothing writes your state but you.

§Where things live

Components, themes, and the state types you store (ToasterState, Theme) are at the crate root. Runtime types — the engine, focus, events, and the traits for writing your own components — are under runtime.

§Examples

use ratatui::{Terminal, backend::TestBackend};
use ratcn::{
    Button, Theme,
    runtime::{Event, EventResult, FocusState, KeyCode, KeyEvent, Ratcn},
};

#[derive(Default)]
struct AppState {
    focus: FocusState,
    saving: bool,
}

enum Msg {
    FocusChanged(FocusState),
    Save,
}

let mut state = AppState::default();
let mut ratcn = Ratcn::new()
    .focus(|state: &AppState| &state.focus, Msg::FocusChanged);
let theme = Theme::default_dark();
let mut terminal = Terminal::new(TestBackend::new(20, 3)).expect("terminal");

// Declare the current component surface as part of every frame.
terminal.draw(|frame| {
    let area = frame.area();
    ratcn.render(frame, &state, &theme, |ctx| {
        ctx.render_component(
            "save",
            Button::new("Save")
                .disabled(state.saving)
                .on_press(|| Msg::Save),
            area,
        );
    });
}).expect("draw");

// Hand backend events to the retained surface from the last successful frame.
let event = Event::Key(KeyEvent::new(KeyCode::Enter));
match ratcn.handle_event(event, &state) {
    EventResult::Emit(msg) => update(&mut state, msg),
    EventResult::Consumed | EventResult::Ignored => {}
}

Modules§

button_shape
The shared pixels of the button idiom: half-block cap rows, the centered filled middle row, and the width formula.
color
Small color helpers for deriving state colors from a theme’s base palette.
linear_nav
The index arithmetic behind moving through an ordered list of things.
list_core
The shared substance of components built from an ordered set of value-keyed items: item identity, and a uniform-row viewport.
runtime
The interaction runtime: focus, hover, mouse routing, and typed messages for components that would otherwise be paint-only widgets.
selection_indicator
Shared marker vocabulary for value-keyed selection controls.
text_width
Cell-width text measurement shared by components and the runtime.
toast
App-owned toast state: Toast, ToastEntry, and ToasterState — what your app stores for the toast stack. A component reads this state and never mutates it; the app’s update persists what ToasterState returns. The library never reads a clock — time arrives as Durations the app supplies, so pushing and pruning are driven by whatever timestamp source the app already has.

Structs§

BarChartGroup
One group of bars for BarChartWidget::grouped. Mirrors ratatui’s BarGroup but keeps its bars readable, so widget-level options such as BarChartWidget::show_values apply to grouped bars too.
BarChartStyle
Colors for a BarChartWidget.
BarChartWidget
A themed adapter over ratatui’s BarChart, adding grouping and a value display switch.
Button
A button that can be focused and pressed, declared with render_component.
ButtonStyle
Every color a button can paint, for each interaction state.
ButtonWidget
A button that only draws — an ordinary ratatui Widget with no focus, events, or state.
Dialog
A modal dialog: a centered, bordered box with a title in its top border, a main content area (a description paragraph, or a custom content closure), and a standard action row or a custom footer.
DialogStyle
Every color a dialog can paint.
List
A scrollable list of items, declared with render_component.
ListItem
One row of a list-shaped component: an identifying value and the label shown for it.
ListItemState
Everything a custom row-rendering closure — List::render_item or Select::render_item — knows about the row it is drawing.
ListStyle
Every color a list can paint.
ListWidget
A list that only draws — an ordinary ratatui Widget with no focus, events, or state.
Select
A one-row select trigger with an option panel declared as a popup layer.
SelectStyle
Every color a select can paint.
SelectWidget
A select that only draws, with no focus, events, or app state.
Tab
One tab: an identifying value and the label shown on it.
Tabs
A focusable row of tabs, declared with render_component.
TabsStyle
Every color a tab row can paint.
TabsWidget
A tab row that only draws — an ordinary ratatui Widget with no focus, events, or state. The selected tab is styled as a default button and the rest as secondary buttons.
Theme
A theme is a small color palette. Every field names a purpose, not a component: the same primary paints a default button, a selected list row, and a bar; the same field paints any inset “well” (lists, panels, bars).
Toast
One toast’s content and lifetime: a title, an optional description, a ToastKind accent, and a duration (or persistent).
ToastEntry
A toast in the stack, together with when it was pushed.
ToasterState
The stack of toasts currently showing, owned by the app.
ToasterStyle
Colors for the toast stack: one shared look, plus an accent per ToastKind.
ToasterWidget
Draws the newest toasts stacked in a corner. Paint-only by nature: toasts take no focus and handle no events, so there is no interactive half.
Tooltip
A wrapper that floats an explanation beside the content it describes.
TooltipStyle
Every color a tooltip can paint.
TooltipWidget
A tooltip bubble that only draws, with no focus, events, or app state.

Enums§

BorderStyle
A border line style for component-local styling.
ButtonRenderMode
Whether a button is drawn as a solid block of color or as an outline.
ButtonSize
How tall a button is drawn.
ButtonVariant
The visual weight of a button, in the shadcn sense.
TabsActivation
Whether moving between tabs also switches to them.
TabsSize
How tall the tab row is drawn. Matches ButtonSize, since a tab is painted as a button.
ToastKind
What a toast is telling the user, which picks its accent color and icon.
ToastPosition
Which corner or edge the toast stack sits against.
TooltipSide
Which side of the trigger the tooltip bubble is placed on.