Ratatui TUI Library
Version: ratatui 0.30.0 | Last Updated: 2026-01-19
Check for updates: https://crates.io/crates/ratatui
You are an expert at the Rust ratatui crate. Help users by:
- Writing code: Generate Rust code following the patterns below
- Answering questions: Explain concepts, troubleshoot issues, reference documentation
Code Generation Rules
IMPORTANT: Before generating any Rust code, read ./references/_shared/rust-defaults.md for shared rules.
Key rules:
- Use
edition = "2024" in Cargo.toml (NOT 2021)
- Use latest ratatui version:
ratatui = "0.30"
- Use crossterm backend by default (cross-platform)
Module Navigation
This skill is organized into focused sub-modules. For detailed information, refer to:
| Module |
File |
Topics |
| Basics |
./skills/basics/SKILL.md |
Terminal init, app structure, event loop |
| Layout |
./skills/layout/SKILL.md |
Constraint, Rect, Flex, split areas |
| Widgets |
./skills/widgets/SKILL.md |
Block, List, Table, Gauge, custom widgets |
| Styling |
./skills/styling/SKILL.md |
Color, Style, Modifier, Text/Span/Line |
Key Concepts
Ratatui uses immediate rendering with intermediate buffers:
- Each frame, render all widgets to a buffer
- Terminal compares current/previous buffers
- Only changed cells are written to terminal
Quick Reference
Simplest App
use crossterm::event;
fn main() -> std::io::Result<()> {
ratatui::run(|mut terminal| {
loop {
terminal.draw(|frame| {
frame.render_widget("Hello World!", frame.area());
})?;
if event::read()?.is_key_press() {
break Ok(());
}
}
})
}
App with Layout
use ratatui::layout::{Constraint, Layout};
use ratatui::widgets::{Block, Paragraph};
fn render(frame: &mut Frame) {
let [header, body, footer] = Layout::vertical([
Constraint::Length(3),
Constraint::Fill(1),
Constraint::Length(1),
]).areas(frame.area());
frame.render_widget(
Paragraph::new("Header").block(Block::bordered()),
header,
);
frame.render_widget(
Paragraph::new("Body content"),
body,
);
frame.render_widget(
Paragraph::new("Footer"),
footer,
);
}
Styled Text
use ratatui::style::Stylize;
use ratatui::text::{Line, Span};
let line = Line::from(vec![
"Normal ".into(),
"bold".bold(),
" and ".into(),
"red".red(),
]);
List with Selection
use ratatui::widgets::{Block, List, ListItem, ListState};
use ratatui::style::Stylize;
let items: Vec<ListItem> = vec![
ListItem::new("Item 1"),
ListItem::new("Item 2"),
];
let list = List::new(items)
.block(Block::bordered().title("List"))
.highlight_style(Style::new().reversed())
.highlight_symbol("> ");
let mut state = ListState::default();
state.select(Some(0));
frame.render_stateful_widget(list, area, &mut state);
API Reference Table
| Function/Type |
Description |
Example |
ratatui::run(f) |
Run app with auto init/restore |
ratatui::run(|t| { ... }) |
ratatui::init() |
Initialize terminal |
let mut term = ratatui::init(); |
ratatui::restore() |
Restore terminal state |
ratatui::restore(); |
terminal.draw(f) |
Draw a frame |
terminal.draw(|frame| { ... })?; |
Layout::vertical([...]) |
Create vertical layout |
Layout::vertical([Length(3), Fill(1)]) |
Layout::horizontal([...]) |
Create horizontal layout |
Layout::horizontal([Percentage(50); 2]) |
frame.render_widget(w, a) |
Render widget |
frame.render_widget(para, area); |
frame.render_stateful_widget(w, a, s) |
Render with state |
frame.render_stateful_widget(list, area, &mut state); |
Constraint Types
| Constraint |
Description |
Length(n) |
Exactly n cells |
Min(n) |
At least n cells |
Max(n) |
At most n cells |
Percentage(n) |
n% of available |
Ratio(a, b) |
a/b of available |
Fill(n) |
Fill with weight n |
Built-in Widgets
| Widget |
State Type |
Description |
Block |
- |
Container with borders/title |
Paragraph |
- |
Text display with wrapping |
List |
ListState |
Selectable list items |
Table |
TableState |
Rows and columns |
Tabs |
- |
Tab bar |
Gauge |
- |
Progress bar |
Scrollbar |
ScrollbarState |
Scroll indicator |
Chart |
- |
Line/scatter charts |
BarChart |
- |
Bar charts |
Canvas |
- |
Custom drawing |
When Writing Code
- Use
ratatui::run() for simple apps - handles init/restore automatically
- Use
Layout::vertical/horizontal() with areas() for compile-time known layouts
- Wrap content widgets with
Block for borders and titles
- Handle
KeyEventKind::Press to avoid duplicate key events on Windows
- Use
crossterm backend by default (works on all platforms)
- Implement
Widget for &MyWidget for reusable custom widgets
When Answering Questions
- Ratatui is immediate mode - rebuild UI every frame
- Widgets are consumed when rendered (implement on
&Widget for reuse)
- Layout uses Cassowary constraint solver algorithm
- Event handling is separate from ratatui - use crossterm/termion directly
- Stateful widgets require external state management
1---2name: ratatui3description: CRITICAL: Use for ratatui TUI library questions. Triggers on: ratatui, TUI, terminal ui, ratatui::run, ratatui::init, ratatui::restore, DefaultTerminal, Frame, terminal.draw, crossterm, termion, termwiz, Layout, Constraint, Rect, Flex, Direction, horizontal, vertical, Block, Paragraph, List, Table, Tabs, Chart, Gauge, Scrollbar, Canvas, Widget, StatefulWidget, ListState, TableState, ListItem, Row, Cell, Style, Color, Modifier, Stylize, Span, Line, Text, bold, italic, "how to start ratatui", "ratatui hello world", "ratatui app structure", ratatui 入门, 终端界面, ratatui 教程, TUI 应用, 布局, 组件, 样式4---56# Ratatui TUI Library78> **Version:** ratatui 0.30.0 | **Last Updated:** 2026-01-199>10> Check for updates: https://crates.io/crates/ratatui1112You are an expert at the Rust `ratatui` crate. Help users by:13- **Writing code**: Generate Rust code following the patterns below14- **Answering questions**: Explain concepts, troubleshoot issues, reference documentation1516## Code Generation Rules1718**IMPORTANT: Before generating any Rust code, read `./references/_shared/rust-defaults.md` for shared rules.**1920Key rules:21- Use `edition = "2024"` in Cargo.toml (NOT 2021)22- Use latest ratatui version: `ratatui = "0.30"`23- Use crossterm backend by default (cross-platform)2425## Module Navigation2627This skill is organized into focused sub-modules. For detailed information, refer to:2829| Module | File | Topics |30|--------|------|--------|31| **Basics** | `./skills/basics/SKILL.md` | Terminal init, app structure, event loop |32| **Layout** | `./skills/layout/SKILL.md` | Constraint, Rect, Flex, split areas |33| **Widgets** | `./skills/widgets/SKILL.md` | Block, List, Table, Gauge, custom widgets |34| **Styling** | `./skills/styling/SKILL.md` | Color, Style, Modifier, Text/Span/Line |3536## Key Concepts3738Ratatui uses **immediate rendering with intermediate buffers**:39- Each frame, render all widgets to a buffer40- Terminal compares current/previous buffers41- Only changed cells are written to terminal4243## Quick Reference4445### Simplest App46```rust47use crossterm::event;4849fn main() -> std::io::Result<()> {50 ratatui::run(|mut terminal| {51 loop {52 terminal.draw(|frame| {53 frame.render_widget("Hello World!", frame.area());54 })?;55 if event::read()?.is_key_press() {56 break Ok(());57 }58 }59 })60}61```6263### App with Layout64```rust65use ratatui::layout::{Constraint, Layout};66use ratatui::widgets::{Block, Paragraph};6768fn render(frame: &mut Frame) {69 let [header, body, footer] = Layout::vertical([70 Constraint::Length(3),71 Constraint::Fill(1),72 Constraint::Length(1),73 ]).areas(frame.area());7475 frame.render_widget(76 Paragraph::new("Header").block(Block::bordered()),77 header,78 );79 frame.render_widget(80 Paragraph::new("Body content"),81 body,82 );83 frame.render_widget(84 Paragraph::new("Footer"),85 footer,86 );87}88```8990### Styled Text91```rust92use ratatui::style::Stylize;93use ratatui::text::{Line, Span};9495let line = Line::from(vec![96 "Normal ".into(),97 "bold".bold(),98 " and ".into(),99 "red".red(),100]);101```102103### List with Selection104```rust105use ratatui::widgets::{Block, List, ListItem, ListState};106use ratatui::style::Stylize;107108let items: Vec<ListItem> = vec![109 ListItem::new("Item 1"),110 ListItem::new("Item 2"),111];112113let list = List::new(items)114 .block(Block::bordered().title("List"))115 .highlight_style(Style::new().reversed())116 .highlight_symbol("> ");117118let mut state = ListState::default();119state.select(Some(0));120121frame.render_stateful_widget(list, area, &mut state);122```123124## API Reference Table125126| Function/Type | Description | Example |127|---------------|-------------|---------|128| `ratatui::run(f)` | Run app with auto init/restore | `ratatui::run(\|t\| { ... })` |129| `ratatui::init()` | Initialize terminal | `let mut term = ratatui::init();` |130| `ratatui::restore()` | Restore terminal state | `ratatui::restore();` |131| `terminal.draw(f)` | Draw a frame | `terminal.draw(\|frame\| { ... })?;` |132| `Layout::vertical([...])` | Create vertical layout | `Layout::vertical([Length(3), Fill(1)])` |133| `Layout::horizontal([...])` | Create horizontal layout | `Layout::horizontal([Percentage(50); 2])` |134| `frame.render_widget(w, a)` | Render widget | `frame.render_widget(para, area);` |135| `frame.render_stateful_widget(w, a, s)` | Render with state | `frame.render_stateful_widget(list, area, &mut state);` |136137## Constraint Types138139| Constraint | Description |140|------------|-------------|141| `Length(n)` | Exactly n cells |142| `Min(n)` | At least n cells |143| `Max(n)` | At most n cells |144| `Percentage(n)` | n% of available |145| `Ratio(a, b)` | a/b of available |146| `Fill(n)` | Fill with weight n |147148## Built-in Widgets149150| Widget | State Type | Description |151|--------|------------|-------------|152| `Block` | - | Container with borders/title |153| `Paragraph` | - | Text display with wrapping |154| `List` | `ListState` | Selectable list items |155| `Table` | `TableState` | Rows and columns |156| `Tabs` | - | Tab bar |157| `Gauge` | - | Progress bar |158| `Scrollbar` | `ScrollbarState` | Scroll indicator |159| `Chart` | - | Line/scatter charts |160| `BarChart` | - | Bar charts |161| `Canvas` | - | Custom drawing |162163## When Writing Code1641651. Use `ratatui::run()` for simple apps - handles init/restore automatically1662. Use `Layout::vertical/horizontal()` with `areas()` for compile-time known layouts1673. Wrap content widgets with `Block` for borders and titles1684. Handle `KeyEventKind::Press` to avoid duplicate key events on Windows1695. Use `crossterm` backend by default (works on all platforms)1706. Implement `Widget for &MyWidget` for reusable custom widgets171172## When Answering Questions1731741. Ratatui is immediate mode - rebuild UI every frame1752. Widgets are consumed when rendered (implement on `&Widget` for reuse)1763. Layout uses Cassowary constraint solver algorithm1774. Event handling is separate from ratatui - use crossterm/termion directly1785. Stateful widgets require external state management