rnk
A React-like declarative terminal UI framework for Rust, inspired by Ink and Bubbletea.
Features
- React-like API: Familiar component model with hooks (
use_signal,use_effect,use_input,use_cmd) - Command System: Elm-inspired side effect management for async tasks, timers, file I/O
- 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: Box, Text, List, Table, Tabs, Progress, Sparkline, BarChart, and more
- Mouse Support: Full mouse event handling
- Cross-platform: Works on Linux, macOS, and Windows
Quick Start
Add to your Cargo.toml:
[]
= "0.6"
Examples
Hello World
use *;
Counter with Keyboard Input
use *;
Streaming Output Demo
use *;
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;
Render APIs
Interactive Applications
// Run interactive TUI application
render.run?;
Static Rendering (Non-interactive)
Render elements to string without running the event loop:
use *;
let element = Boxnew
.border_style
.child
.into_element;
// Render with specific width
let output = render_to_string;
println!;
// Render with auto-detected terminal width
let output = render_to_string_auto;
println!;
Components
Box
Flexbox container with full layout support.
Boxnew
.flex_direction
.justify_content
.align_items
.padding
.margin
.width
.height
.border_style
.border_color
.background
.child
.into_element
Border Styles: None, Single, Double, Round, Bold, Custom(chars)
Per-side Border Colors:
Boxnew
.border_style
.border_top_color
.border_bottom_color
.border_left_color
.border_right_color
Text
Styled text with colors and formatting.
new
.color
.background_color
.bold
.italic
.underline
.strikethrough
.dim
.into_element
Rich Text with Spans:
builder
.span
.span_styled
.span
.span_styled
.build
.into_element
List
Selectable list with keyboard navigation.
new
.items
.selected
.highlight_style
.on_select
.into_element
Table
Data table with headers and styling.
new
.headers
.rows
.column_widths
.header_style
.into_element
Tabs
Tab navigation component.
new
.tabs
.selected
.on_change
.into_element
Progress / Gauge
Progress bars and gauges.
// Simple progress bar
new
.progress // 75%
.width
.filled_char
.empty_char
.into_element
// Gauge with label
new
.ratio
.label
.into_element
Sparkline
Inline data visualization.
new
.data
.width
.into_element
BarChart
Horizontal and vertical bar charts.
new
.data
.bar_width
.bar_gap
.into_element
Static
Permanent output that persists above dynamic UI.
new.into_element
Transform
Transform child text content.
new
.child
.into_element
Spacer / Newline
Layout helpers.
Boxnew
.flex_direction
.child
.child // Flexible space
.child
.into_element
// Add vertical space
new.into_element
Spinner
Animated loading indicator.
new
.style
.label
.into_element
Message
Styled message boxes for info, success, warning, error.
info
success
warning
error
Hooks
use_signal
Reactive state management.
let count = use_signal;
// Read value
let value = count.get;
// Update value
count.set;
// Update with function
count.update;
use_effect
Side effects with dependencies.
let data = use_signal;
use_effect;
use_input
Keyboard input handling.
use_input;
Key struct fields:
up_arrow,down_arrow,left_arrow,right_arrowpage_up,page_down,home,endreturn_key,escape,tab,backspace,deletectrl,shift,alt(modifier keys)
use_mouse
Mouse event handling.
use_mouse;
use_focus
Focus management for form inputs.
let focus_state = use_focus;
if focus_state.is_focused
use_scroll
Scroll state management.
let scroll = use_scroll;
// Configure content and viewport sizes
scroll.set_content_size;
scroll.set_viewport_size;
use_input;
// Get current scroll position
let offset_y = scroll.offset_y;
use_app
Application control.
let app = use_app;
use_input;
use_cmd
Elm-inspired command system for side effects (async tasks, timers, file I/O).
use *;
use Cmd;
use Duration;
Available Commands:
// No-op command
none
// Batch multiple commands
batch
// Delay execution
sleep
// Async task with callback
perform
// Chain commands
cmd.and_then
// File operations
read_file
write_file
// Spawn process
spawn
use_window_title
Set terminal window title.
use_window_title;
Cross-thread Rendering
When updating state from background threads:
use thread;
use ;
Println API
Print persistent messages above the UI (inline mode only):
// Simple text
println;
// Formatted text
println;
// Rich elements
let banner = Boxnew
.border_style
.child
.into_element;
println;
Colors
// Basic colors
Black, Red, Green, Yellow,
Blue, Magenta, Cyan, White,
Gray
// 256 colors
Ansi256 // 0-255
// RGB colors
Rgb
Testing
rnk provides testing utilities for verifying UI components:
use ;
Running Examples
# Hello world
# Interactive counter
# Streaming output demo
# Static rendering API demo
# GLM chat demo
Architecture
src/
├── components/ # UI components (Box, Text, List, etc.)
├── core/ # Element, Style, Color primitives
├── hooks/ # React-like hooks (use_signal, use_effect, etc.)
├── layout/ # Taffy-based flexbox layout engine
├── renderer/ # Terminal rendering, App runner
└── testing/ # Test utilities
Comparison with Ink/Bubbletea
| Feature | rnk | Ink | Bubbletea |
|---|---|---|---|
| Language | Rust | JavaScript | Go |
| Rendering | Line-level diff | Line-level diff | Line-level diff |
| Layout | Flexbox (Taffy) | Flexbox (Yoga) | Manual |
| State | Hooks | React hooks | Model-Update |
| Inline mode | ✓ | ✓ | ✓ |
| Fullscreen | ✓ | ✓ | ✓ |
| Println | ✓ | Static component | tea.Println |
| Cross-thread | request_render() | - | tea.Program.Send |
License
MIT