Skip to content

Introduction ​

ratcn is an opinionated library of beautifully designed terminal UI components for Ratatui. You copy them into your application code, theme them, and make them your own.

Every component paints through a plain Ratatui widget, so it fits into the app you already have. Add the ratcn engine and the components come alive: it handles focus, keyboard and mouse input, hover, and layers, and tells your app what the user did.

ui = f(state): your app state is rendered into the UI, user input becomes a message, and update applies the message to the state.ui = f(state)Stateowned by your appUIwhat is on screenMessagewhat the user didrenderinputupdate

Your app stays in charge. The state lives in your app, and the screen is a function of it: each frame describes the UI from that state, and components report what happened as messages for your app to apply. The components are yours as well. When one doesn't do what you need, copy its source into your project and change it.

Terminal apps can be as pleasant to use as anything on the web. Buttons light up under the pointer, fields take clicks and selections, and the patterns you know from the web are here too: toasts, tooltips, dropdowns, and modal dialogs that float above the rest of your app.

See it live ​

The components run in your terminal right now, with nothing to install:

sh
ssh ratcn.com

The showcase lets you browse every component, switch themes, drag cards across a Kanban board, and try full demo apps with your keyboard and mouse. The previews on the component pages run live in your browser as well.

Widgets, the engine, or both ​

Each component comes in up to two parts, and each part works on its own:

  • Paint-only widgets, such as ButtonWidget and BarChartWidget, are ordinary Ratatui widgets. They drop into any Ratatui app with frame.render_widget(...): no engine, no message type, no change to how your app already works.
  • Interactive components, such as Button, List, Tabs, and Dialog, add focus, keyboard and mouse handling, and messages on top. You declare them through the engine, the Ratcn runtime.

If you already have focus and event handling you like, use the widgets alone and keep it. Nothing built that way is second-class: most interactive components paint through these same widgets, and you can adopt the engine later, one component at a time.

Your app stays in charge ​

The engine enters your app at two calls, and leaves the rest of your loop alone:

  • Ratcn::render(frame, area, state, theme, declare) declares which components are on screen this frame, and paints them.
  • Ratcn::handle_event(event, state) routes one input event, and may hand you a message back.

Components never write your state. A Button emits a message when pressed; a List reads its selection from your state and emits the item the user chose. Your update function applies the message, and it is the only place state changes. State and messages covers the rules everything else builds on.

Layers ​

Some things belong above the rest of the screen. The engine paints them on layers, each with its own rules:

  • Hints explain, like a tooltip. They paint on top and never get in the way of the pointer.
  • Popups offer a choice, like a dropdown or a menu. They take the clicks that land on them, without dimming anything or stealing focus.
  • Modals take over, like a dialog. They dim what is beneath, hold focus, and keep keys and clicks to themselves until they close.

A layer can be declared from anywhere in your UI. See Layers and modals.

Components ​

Button, Input, TextArea, List, ScrollArea, Select, Tabs, Dialog, Toast, BarChart, Tooltip, Checkbox, Cycle, and Progress. Each page has a live preview. If there is a component or pattern you would like to see, please open an issue.

The concepts ​

Each concept page covers one idea in depth. Roughly in reading order:

  • State and messages: the ownership rules. Your app owns state, components read it and emit messages, and update is the only writer.
  • Rendering and event routing: how a frame is declared, how the engine remembers it, and how events find the right component.
  • Focus, hover, and identity: how components get stable identities, how Tab traversal works, and why focus lives in your state while hover lives in the engine.
  • Keyboard: every key the components respond to, and the rules that decide which component claims a key.
  • Layers and modals: dialogs, overlays, and paint ordering.
  • Themes: built-in presets and authoring your own palette.
  • Host integration: opening and restoring the terminal with a Session, the shape of the event loop, and running in the browser with Ratzilla.
  • Mouse input and Dragging: enabling mouse support, and how clicks, hover, and drags reach components.
  • Structuring a larger app: splitting state, messages, and rendering per screen once one module is not enough.
  • Custom components: writing your own components, composites included, with the same powers as the built-ins.

Getting started sets up a project and puts a first app on screen, and Demos lists every runnable example, including three full applications.