rnk
A React-like declarative terminal UI framework for Rust, inspired by Ink and Bubbletea.
Version Status
The Crates.io badge above is the source of truth for published installs. This
checkout currently declares 0.19.3; when the checkout is ahead of the latest
published release, use the git dependency below for the latest source version.
Release notes live in CHANGELOG.md; older published release
artifacts remain available on
GitHub Releases.
Current maturity planning and issue acceptance criteria live in docs/RNK_MATURITY_SPEC.md. The current public API boundary and pre-1.0 semver policy live in docs/API_STABILITY.md. The 5-minute first app path lives in docs/getting-started.md. Interactive component state and event contracts live in docs/INTERACTIVE_COMPONENT_CONTRACTS.md. The recommended core component contracts live in docs/CORE_COMPONENT_CONTRACTS.md. Focus, accessibility, and input semantics live in docs/FOCUS_ACCESSIBILITY_INPUT.md.
Features
- React-like API: Familiar component model with hooks (
use_signal,use_state,use_ref,use_context,use_effect,use_layout_effect,use_input,use_cmd) - Command System: Elm-inspired side effect management for async tasks, timers, file I/O
- Type-safe Commands:
Cmd<M>for compile-time message type checking - Declarative Macros:
row!,col!,text!for concise UI building - Declarative UI: Build TUIs with composable components
- Flexbox Layout: Powered by Taffy for flexible layouts
- Inline Mode (default): Output persists in terminal history (like Ink/Bubbletea)
- Fullscreen Mode: Uses alternate screen buffer (like vim)
- Line-level Diff Rendering: Only changed lines are redrawn for efficiency
- Persistent Output:
println()API for messages that persist above the UI - Cross-thread Rendering:
request_render()for async/multi-threaded apps - Rich Components: 45+ components including Box, Text, List, Table, Tree, Modal, LineChart, Calendar, CodeEditor, and more
- Animation System: Keyframe animations with 28 easing functions
- Chainable Style API: CSS-like fluent styling with
.fg(),.bg(),.bold(),.p(),.m() - Mouse Support: Full mouse event handling
- Bracketed Paste: Distinguish between typed and pasted text
- Theme System: Centralized theming with semantic colors, design tokens, variants, and shared action styles
- Cross-platform: Works on Linux, macOS, and Windows
When To Use rnk
Use rnk when you want to build an interactive Rust CLI app with a declarative
component tree, hooks, flexbox-style layout, typed side effects, and built-in
terminal widgets.
It is a good fit for agent UIs, chat-style tools, dashboards, forms, selectors, and terminal workflows where application code should read more like a component tree than a manual draw loop.
Prefer Ratatui when you want lower-level control over every frame or already use
its widget ecosystem. Prefer plain crossterm when you only need terminal input
or a few styled lines.
Recent Improvements
- Added core hooks:
use_state,use_ref,create_context/use_context,use_layout_effect - Integrated dirty-row rendering path in
Output::render() - Improved command executor startup resilience (runtime creation failure now degrades safely)
- Added
docs/vibe/design-guard-and-fixflow.mdfor step-by-step design issue tracking and fixes
Quick Start
rnk is distributed as a Rust crate for Cargo projects. Add the latest published Crates.io release:
If you edit Cargo.toml manually, use the current version shown on the Crates.io badge or package page.
For the latest source version before the next release is published:
[]
= { = "https://github.com/majiayu000/rnk" }
The rnk binary target is a minimal repository demo and does not expose a
standalone CLI surface. Keep installation docs centered on Cargo dependencies
until a dedicated CLI distribution is added.
For a copy-paste path from an empty Cargo project to an interactive TUI, follow docs/getting-started.md.
Limitations
- The public distribution is the Rust crate API. The
rnkbinary target is a minimal repository demo, not a supported end-user CLI. - Terminal feature support depends on the user's terminal emulator. Mouse input, hyperlinks, bracketed paste, alternate-screen behavior, and color rendering may vary by platform and terminal. See docs/TERMINAL_COMPATIBILITY.md for the current compatibility matrix and Unicode/ANSI behavior contract.
rnk-style,rnk-style-core, andrnk-iconsare workspace crates with their own package versions. Their release cadence may differ from the top-levelrnkcrate.- The
httpfeature is optional. Applications that need HTTP support must enable it explicitly. - The framework targets Rust
1.88and newer.
Examples
Recommended first examples:
The full examples index lives at examples/README.md.
Hello World
use *;
Using Declarative Macros
use *;
use ;
Counter with Keyboard Input
use *;
Type-safe Commands with Cmd
use *;
use Cmd;
use Duration;
Render Modes
Inline Mode (Default)
Output appears at current cursor position and persists in terminal history.
render.run?; // Inline mode (default)
render.inline.run?; // Explicit inline mode
Fullscreen Mode
Uses alternate screen buffer. Content is cleared on exit.
render.fullscreen.run?;
Configuration Options
render
.fullscreen // Use alternate screen
.fps // Target 30 FPS (default: 60)
.exit_on_ctrl_c // Handle Ctrl+C manually
.run?;
Runtime Mode Switching
Switch between modes at runtime:
let app = use_app;
use_input;
Components
Layout Components
| Component | Description |
|---|---|
Box |
Flexbox container with full layout support |
Spacer |
Flexible space filler |
Newline |
Vertical space |
Transform |
Transform child text content |
Text & Display
| Component | Description |
|---|---|
Text |
Styled text with colors and formatting |
Gradient |
Text with gradient colors |
Hyperlink |
Clickable terminal hyperlinks |
Spinner |
Animated loading indicator |
Cursor |
Blinking cursor component |
Data Display
| Component | Description |
|---|---|
List |
Selectable list with keyboard navigation |
Table |
Data table with headers and styling |
Tree |
Hierarchical tree view |
Progress / Gauge |
Progress bars |
Sparkline |
Inline data visualization |
BarChart |
Horizontal/vertical bar charts |
Scrollbar |
Scrollbar indicator |
Input Components
| Component | Description |
|---|---|
TextInput |
Single-line text input |
TextArea |
Multi-line text editor with vim keybindings |
SelectInput |
Dropdown-style selection |
MultiSelect |
Multiple item selection |
Confirm |
Yes/No confirmation dialog |
FilePicker |
File system browser |
Navigation
| Component | Description |
|---|---|
Tabs |
Tab navigation |
Paginator |
Page navigation (dots, numbers, arrows) |
Viewport |
Scrollable content viewport |
Help |
Keyboard shortcut help display |
Feedback & Overlay
| Component | Description |
|---|---|
Modal |
Modal overlay |
Dialog |
Dialog box with buttons |
Notification / Toast |
Notification messages |
Message |
Styled message boxes (info, success, warning, error) |
Static |
Permanent output above dynamic UI |
Theming
| Component | Description |
|---|---|
Theme |
Centralized theme configuration |
ThemeBuilder |
Fluent theme construction |
Example: Box
Boxnew
.flex_direction
.justify_content
.align_items
.padding
.margin
.width
.height
.border_style
.border_color
.background
.child
.into_element
Example: Tree
let root = new
.child
.child;
new
.expanded
.selected
.into_element
Example: Modal
new
.visible
.align
.child
.into_element
Example: Notification
new
.items
.position
.max_visible
.into_element
Hooks
State Management
| Hook | Description |
|---|---|
use_signal |
Reactive state management |
use_state |
Simplified (value, setter) state API |
use_ref |
Mutable persistent value without re-render |
create_context / use_context |
Context-based value sharing |
use_memo |
Memoized computation |
use_callback |
Memoized callback |
Effects & Commands
| Hook | Description |
|---|---|
use_effect |
Side effects with dependencies |
use_effect_once |
One-time side effect |
use_layout_effect |
Layout effect API (currently aligned with use_effect) |
use_layout_effect_once |
One-time layout effect |
use_cmd |
Command execution with dependencies |
use_cmd_once |
One-time command execution |
Input
| Hook | Description |
|---|---|
use_input |
Keyboard input handling |
use_mouse |
Mouse event handling |
use_paste |
Bracketed paste handling |
use_text_input |
Text input state management |
Focus & Navigation
| Hook | Description |
|---|---|
use_focus |
Focus state for a component |
use_scoped_focus |
Focus state inside a traversal scope |
use_focus_manager |
Global focus management |
use_focus_traversal |
Default Tab / Shift+Tab focus traversal |
use_focus_traversal_in_scope |
Scoped Tab / Shift+Tab focus traversal |
use_scroll |
Scroll state management |
Application
| Hook | Description |
|---|---|
use_app |
Application control (exit, etc.) |
use_window_title |
Set terminal window title |
use_frame_rate |
Frame rate monitoring |
use_measure |
Measure element dimensions |
use_stdin / use_stdout / use_stderr |
Stdio access |
Example: use_paste
use_paste;
Example: use_memo
let items = use_signal;
// Only recomputes when items change
let sum = use_memo;
Command System
Basic Commands
use Cmd;
// No-op command
none
// Execute multiple commands concurrently
batch
// Execute commands sequentially
sequence
// Delay execution
sleep
// Timer tick (single)
tick
// System clock aligned tick
every
// Async task
perform
// Chain commands
cmd.and_then
Terminal Control Commands
// Clear screen
clear_screen
// Cursor control
hide_cursor
show_cursor
// Window title
set_window_title
// Request window size (triggers resize event)
window_size
// Screen mode
enter_alt_screen
exit_alt_screen
// Mouse
enable_mouse
disable_mouse
// Bracketed paste
enable_bracketed_paste
disable_bracketed_paste
External Process Execution
// Execute external process (suspends TUI)
exec_cmd
Type-safe Commands (Cmd)
use Cmd;
// Compiler ensures all callbacks return Msg
let cmd: = perform;
Declarative Macros
use ;
// Vertical layout
col!
// Horizontal layout
row!
// Formatted text
text!
// Styled text
styled_text!
// Conditional rendering
when!
// List from iterator
list!
// List with index
list_indexed!
Theme System
use ;
use Color;
// Create custom theme
let theme = new
.primary
.secondary
.success
.warning
.error
.build;
// Set global theme
set_theme;
// Use theme colors
let color = get_theme.semantic_color;
// Use derived design tokens and variants
let tokens = get_theme.design_tokens;
let focused = get_theme.variant_style;
// Use shared action styling for button-like labels
let action = new
.role
.state
.into_element;
// Scoped theme
let dark_theme = dark;
with_theme;
See Design Tokens And Component Variants for the current token and variant contract.
Cross-thread Rendering
use thread;
Testing
use ;
Running Examples
The list below is a curated representative set, not a generated index. Cargo
auto-discovers the full top-level example set from examples/*.rs. See
examples/README.md for the categorized tutorial,
showcase, component demo, debug, and internal index.
# Recommended first run
# Basic examples
# Showcase applications
# Component demos
# Advanced examples
# Note: use `--example` (not `cargo run example <name>`)
Architecture
src/
├── animation/ # Keyframe animations, easing functions, spring physics
├── cmd/ # Command system (Cmd<M>, executor)
├── components/ # 45+ UI components
├── core/ # Element, Style, Color primitives
├── hooks/ # React-like hooks (use_signal, use_animation, use_transition)
├── layout/ # Taffy-based flexbox layout engine
├── macros.rs # Declarative UI macros
├── renderer/ # Terminal rendering, App runner
├── runtime/ # Signal handling, environment detection
└── testing/ # TestRenderer, TestHarness, assertions
Comparison with Ink/Bubbletea
See docs/COMPARISON.md for the current
evidence-based comparison. In short, rnk is a Rust-native, hook/signal-driven,
Taffy-backed terminal UI framework. Feature parity with Ink, Bubbletea, and
Ratatui depends on the specific terminal behavior and application pattern being
compared.
License
MIT