/rɪˈvjuː/ — Re + Vue — A Vue-style TUI framework for Rust
Quick Start · Tutorials · Examples · Documentation · Contributing
Build terminal UIs like you build web apps — with CSS and reactive state.
- CSS Styling — Write styles in familiar CSS syntax with variables, selectors, and animations
- Reactive State — Vue-inspired
Signal/Computed/Effectsystem for automatic UI updates - 100+ Widgets — Rich component library: inputs, tables, charts, markdown, images, and more
- Hot Reload — See CSS changes instantly without restarting your app
- Developer Tools — Widget inspector, snapshot testing, and performance profiler built-in
- Single Binary — Pure Rust, no runtime dependencies, blazing fast
cargo add revueuse revue::prelude::*;
fn main() -> Result<()> {
let mut app = App::builder()
.style("styles.css")
.build();
let counter = Counter::new();
app.run(counter, |event, counter, _app| {
if let Event::Key(key) = event {
counter.handle_key(&key.key)
} else {
false
}
})
}
struct Counter {
count: Signal<i32>,
}
impl Counter {
fn new() -> Self {
Self { count: signal(0) }
}
fn handle_key(&mut self, key: &Key) -> bool {
match key {
Key::Up => { self.count.update(|n| *n += 1); true }
Key::Down => { self.count.update(|n| *n -= 1); true }
_ => false,
}
}
}
impl View for Counter {
fn render(&self, ctx: &mut RenderContext) {
let count = self.count.get();
vstack()
.class("container")
.child(Text::new(format!("Count: {}", count)).bold())
.child(
hstack().gap(1)
.child(Text::new("↑/↓ to change, q to quit"))
)
.render(ctx);
}
}/* styles.css */
.container {
padding: 2;
gap: 1;
border: rounded cyan;
align-items: center;
}
button {
padding: 0 2;
background: var(--primary);
}
button:hover {
background: var(--primary-dark);
}Automatic validation with type-safe form state:
use revue::patterns::form::FormState;
let form = FormState::new()
.field("email", |f| f
.label("Email")
.email()
.required())
.field("password", |f| f
.label("Password")
.password()
.min_length(8))
.field("confirm", |f| f
.label("Confirm Password")
.password()
.matches("password"))
.build();
// Reactive validation - errors auto-update when values change
form.set_value("email", "invalid");
assert!(!form.is_valid());
form.set_value("email", "user@example.com");
// Validation automatically recalculatesSee Forms Tutorial for complete guide.
Rich animations with easing functions and keyframes:
use revue::animation::{Animation, Easing};
// Fade in with custom easing
text("Hello!")
.animation(Animation::fade_in()
.duration(300)
.easing(Easing::EaseInOutCubic))
// Slide in from left
text("Welcome!")
.animation(Animation::slide_in_left()
.duration(500)
.delay(100))
// Keyframe animation
text("Pulsing!")
.animation(Animation::keyframe(|keyframes| {
keyframes
.at(0, |kf| kf.scale(1.0).opacity(1.0))
.at(50, |kf| kf.scale(1.2).opacity(0.8))
.at(100, |kf| kf.scale(1.0).opacity(1.0))
}))Execute background tasks without blocking the UI:
use revue::worker::{WorkerHandle, WorkerPool};
// Spawn blocking task
let handle = WorkerHandle::spawn_blocking(|| {
heavy_computation()
});
// Use worker pool
let pool = WorkerPool::new(4);
pool.submit(|| {
fetch_data_from_api()
});
// Get result when ready
if let Some(result) = handle.try_recv() {
// Update UI with result
}CSS changes update instantly without restart:
let mut app = App::builder()
.style("styles.css")
.hot_reload(true) // Enable hot reload
.build();
app.run(view, handler)?;Edit styles.css and see changes immediately - no restart needed!
Built-in widget inspector and profiler:
let mut app = App::builder()
.devtools(true) // Enable devtools
.build();
app.run(view, handler)?;Keyboard shortcuts:
Ctrl+D— Toggle devtools overlayCtrl+I— Open widget inspector
Features:
- Widget inspector with computed styles
- Performance profiler for identifying bottlenecks
- Snapshot testing for UI regression testing
| Category | Components |
|---|---|
| Layout | vstack hstack grid scroll tabs accordion splitter layers |
| Input | input textarea select checkbox radio switch slider number_input |
| Forms | form form_field — Built-in validation system |
| Display | text markdown table tree list progress badge image presentation |
| Feedback | modal toast notification tooltip popover alert callout |
| Charts | barchart line_chart sparkline heatmap gauge boxplot histogram |
| Advanced | rich_text_editor json_viewer csv_viewer diagram command_palette |
| Dev | debug_overlay snapshot_test profiler |
100+ Widgets — See FEATURES.md for complete catalog
Automatic validation with type-safe form state:
use revue::patterns::form::FormState;
let form = FormState::new()
.field("email", |f| f
.label("Email")
.email()
.required())
.field("password", |f| f
.label("Password")
.password()
.min_length(8))
.field("confirm", |f| f
.label("Confirm Password")
.password()
.matches("password"))
.build();
// Reactive validation - errors auto-update when values change
form.set_value("email", "invalid");
assert!(!form.is_valid());
form.set_value("email", "user@example.com");
// Validation automatically recalculatesSee Forms Tutorial for complete guide.
Rich animations with easing functions and keyframes:
use revue::animation::{Animation, Easing};
// Fade in with custom easing
text("Hello!")
.animation(Animation::fade_in()
.duration(300)
.easing(Easing::EaseInOutCubic))
// Slide in from left
text("Welcome!")
.animation(Animation::slide_in_left()
.duration(500)
.delay(100))
// Keyframe animation
text("Pulsing!")
.animation(Animation::keyframe(|keyframes| {
keyframes
.at(0, |kf| kf.scale(1.0).opacity(1.0))
.at(50, |kf| kf.scale(1.2).opacity(0.8))
.at(100, |kf| kf.scale(1.0).opacity(1.0))
}))Execute background tasks without blocking the UI:
use revue::worker::{WorkerHandle, WorkerPool};
// Spawn blocking task
let handle = WorkerHandle::spawn_blocking(|| {
heavy_computation()
});
// Use worker pool
let pool = WorkerPool::new(4);
pool.submit(|| {
fetch_data_from_api()
});
// Get result when ready
if let Some(result) = handle.try_recv() {
// Update UI with result
}CSS changes update instantly without restart:
let mut app = App::builder()
.style("styles.css")
.hot_reload(true) // Enable hot reload
.build();
app.run(view, handler)?;Edit styles.css and see changes immediately - no restart needed!
Built-in widget inspector and profiler:
let mut app = App::builder()
.devtools(true) // Enable devtools
.build();
app.run(view, handler)?;Keyboard shortcuts:
Ctrl+D— Toggle devtools overlayCtrl+I— Open widget inspector
Features:
- Widget inspector with computed styles
- Performance profiler for identifying bottlenecks
- Snapshot testing for UI regression testing
# Basics
cargo run --example counter # Reactive counter with Signal
cargo run --example todo # Full-featured todo app
cargo run --example hello_world # Minimal "Hello World"
# UI Components
cargo run --example form # Form validation demo
cargo run --example dashboard # Charts and data widgets
cargo run --example gallery # Widget showcase
# Advanced
cargo run --example animations # Animation system
cargo run --example worker # Background tasks
cargo run --example slideshow # Terminal presentations
cargo run --example ide # Rich text editor
# Real-world
cargo run --example chat # Multi-user chat
cargo run --example data_explorer # JSON/CSV viewerBrowse all examples in the examples/ directory.
| Tutorial | Description | Time |
|---|---|---|
| Getting Started | Install and create your first app | 5 min |
| Counter App | Learn state management with signals | 10 min |
| Todo App | Build a full-featured todo list | 20 min |
| Reactive State | Deep dive into Signal, Computed, Effect | 15 min |
| Styling | CSS styling and theming | 15 min |
| Forms | Form handling with validation | 20 min |
| Guide | Description |
|---|---|
| App Builder | Complete App Builder API reference |
| Styling | CSS properties, selectors, and theming |
| State Management | Reactive state with signals |
| Testing | Test your TUI apps |
| Accessibility | Build inclusive apps |
| Performance | Optimization tips |
| Plugin System | Create and use plugins |
| Revue | ratatui | reratui | Cursive | Textual | |
|---|---|---|---|---|---|
| Type | Framework | Library | Framework | Framework | Framework |
| Language | Rust | Rust | Rust | Rust | Python |
| Architecture | Retained | Immediate | Immediate | Retained | Retained |
| Styling | CSS Files | Inline | Inline-style | TOML | CSS |
| State | Signals | Manual | Hooks | Event | Reactive |
| Widgets | 100+ | 15 built-in | Components | 40+ | 35+ |
| Layout | Flex+Grid | Constraint | Flex | Dock | Dock+Grid |
| Forms | ✅ Built-in | ❌ | ❌ | ❌ | ✅ |
| Animation | ✅ Tween+Keyframes | ❌ | ❌ | ❌ | ✅ |
| Worker Pool | ✅ | ❌ | ❌ | ❌ | ❌ |
| Hot Reload | ✅ | ❌ | ❌ | ❌ | ✅ |
| Devtools | ✅ | ❌ | ❌ | ❌ | ✅ |
| Single Binary | ✅ | ✅ | ✅ | ✅ | ❌ |
Note: ratatui is a low-level TUI library (like React's DOM), while reratui is a React-like framework built on top of ratatui. See Framework Comparison for detailed analysis.
- Getting Started — 5-minute tutorial
- Widget Catalog — Complete widget reference
- App Builder Guide — Complete App Builder API reference
- Styling Guide — CSS properties and theming
- State Management — Signals, Computed, Effects
- API Reference — Full API documentation
- Architecture — System design
We welcome contributions! See CONTRIBUTING.md for guidelines.
git clone https://github.com/hawk90/revue.git
cd revue && cargo testDevelopment workflow:
- Fork the repository
- Create a feature branch (
feat/your-feature,fix/your-bug) - Make your changes with tests
- Run
cargo testandcargo clippy - Submit a pull request
MIT License — see LICENSE for details.