Ratatui Widgets Skill
Version: ratatui 0.30.0 | Last Updated: 2026-01-17
Check for updates: https://crates.io/crates/ratatui
You are an expert at the Rust ratatui crate widgets. Help users by:
- Writing code: Generate Rust code following the patterns below
- Answering questions: Explain concepts, troubleshoot issues, reference documentation
Documentation
Refer to the local files for detailed documentation:
../../references/widgets/built-in-widgets.md - All widget types and usage
../../references/widgets/custom-widgets.md - Creating custom widgets
../../references/_shared/rust-defaults.md - Rust code generation defaults
IMPORTANT: Documentation Completeness Check
Before answering questions, Claude MUST:
- Read the relevant reference file(s) listed above
- If file read fails or file is empty:
- Inform user: "本地文档不完整,建议运行
/sync-crate-skills ratatui --force 更新文档"
- Still answer based on SKILL.md patterns + built-in knowledge
- If reference file exists, incorporate its content into the answer
Widget Traits
| Trait |
Description |
Render Method |
Widget |
Stateless, consumed on render |
frame.render_widget(w, area) |
StatefulWidget |
Has external state |
frame.render_stateful_widget(w, area, &mut state) |
WidgetRef |
Render by reference (unstable) |
w.render_ref(area, buf) |
Key Patterns
Pattern 1: Block with Content
use ratatui::widgets::{Block, Paragraph};
let block = Block::bordered()
.title("My Block")
.title_bottom("Footer");
let paragraph = Paragraph::new("Content here")
.block(block);
frame.render_widget(paragraph, area);
Pattern 2: List with Selection
use ratatui::widgets::{Block, List, ListItem, ListState};
use ratatui::style::{Style, Stylize};
let items: Vec<ListItem> = vec![
ListItem::new("Item 1"),
ListItem::new("Item 2"),
ListItem::new("Item 3"),
];
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);
Pattern 3: Table with Selection
use ratatui::widgets::{Block, Cell, Row, Table, TableState};
use ratatui::style::Stylize;
use ratatui::layout::Constraint;
let rows = vec![
Row::new(vec![Cell::from("Alice"), Cell::from("25")]),
Row::new(vec![Cell::from("Bob"), Cell::from("30")]),
];
let table = Table::new(rows, [Constraint::Percentage(70), Constraint::Percentage(30)])
.block(Block::bordered().title("Users"))
.header(Row::new(vec!["Name", "Age"]).bold())
.highlight_style(Style::new().reversed());
let mut state = TableState::default();
state.select(Some(0));
frame.render_stateful_widget(table, area, &mut state);
Pattern 4: Tabs
use ratatui::widgets::{Block, Tabs};
use ratatui::style::Stylize;
let tabs = Tabs::new(vec!["Tab 1", "Tab 2", "Tab 3"])
.block(Block::bordered())
.select(0)
.highlight_style(Style::new().bold().yellow());
frame.render_widget(tabs, area);
Pattern 5: Gauge/Progress
use ratatui::widgets::{Block, Gauge};
use ratatui::style::{Color, Style};
let gauge = Gauge::default()
.block(Block::bordered().title("Progress"))
.gauge_style(Style::new().fg(Color::Green))
.percent(75)
.label("75%");
frame.render_widget(gauge, area);
API Reference Table
| Widget |
Key Methods |
State Type |
Block |
bordered(), title(), padding() |
None |
Paragraph |
new(), block(), wrap(), scroll() |
None |
List |
new(), highlight_style(), highlight_symbol() |
ListState |
Table |
new(), header(), widths(), highlight_style() |
TableState |
Tabs |
new(), select(), highlight_style() |
None |
Gauge |
percent(), ratio(), label() |
None |
LineGauge |
ratio(), line_set() |
None |
Scrollbar |
orientation(), thumb_symbol() |
ScrollbarState |
Sparkline |
data(), max(), bar_set() |
None |
Chart |
datasets(), x_axis(), y_axis() |
None |
BarChart |
data(), bar_width(), bar_gap() |
None |
Canvas |
paint(), marker(), x_bounds(), y_bounds() |
None |
Clear |
(none) |
None |
When Writing Code
- Wrap content widgets with
Block for borders and titles
- Use
ListState::default().select(Some(0)) to start with first item selected
- Navigate stateful widgets by modifying state, not widget
- Use
Clear before rendering popups to erase underlying content
- Implement
Widget for &MyWidget for reusable custom widgets
When Answering Questions
- Widgets are consumed when rendered (use references for reuse)
- Stateful widgets require external state management
- Selection uses
Option<usize> - None means nothing selected
- Most widgets accept
Into<Text> for content
- Block is a container widget, not standalone content
1---2name: ratatui-widgets3description: CRITICAL: Use for ratatui widgets and UI components. Triggers on: Block, Paragraph, List, Table, Tabs, Chart, Gauge, Scrollbar, Canvas, Widget, StatefulWidget, ListState, TableState, ListItem, Row, Cell, BarChart, Sparkline, LineGauge, Clear, render_widget, render_stateful_widget, "custom widget", "create widget", "ratatui widget", 组件, 控件, 列表, 表格, 进度条, 图表, 自定义组件4---56# Ratatui Widgets Skill78> **Version:** ratatui 0.30.0 | **Last Updated:** 2026-01-179>10> Check for updates: https://crates.io/crates/ratatui1112You are an expert at the Rust `ratatui` crate widgets. Help users by:13- **Writing code**: Generate Rust code following the patterns below14- **Answering questions**: Explain concepts, troubleshoot issues, reference documentation1516## Documentation1718Refer to the local files for detailed documentation:19- `../../references/widgets/built-in-widgets.md` - All widget types and usage20- `../../references/widgets/custom-widgets.md` - Creating custom widgets21- `../../references/_shared/rust-defaults.md` - Rust code generation defaults2223## IMPORTANT: Documentation Completeness Check2425**Before answering questions, Claude MUST:**26271. Read the relevant reference file(s) listed above282. If file read fails or file is empty:29 - Inform user: "本地文档不完整,建议运行 `/sync-crate-skills ratatui --force` 更新文档"30 - Still answer based on SKILL.md patterns + built-in knowledge313. If reference file exists, incorporate its content into the answer3233## Widget Traits3435| Trait | Description | Render Method |36|-------|-------------|---------------|37| `Widget` | Stateless, consumed on render | `frame.render_widget(w, area)` |38| `StatefulWidget` | Has external state | `frame.render_stateful_widget(w, area, &mut state)` |39| `WidgetRef` | Render by reference (unstable) | `w.render_ref(area, buf)` |4041## Key Patterns4243### Pattern 1: Block with Content4445```rust46use ratatui::widgets::{Block, Paragraph};4748let block = Block::bordered()49 .title("My Block")50 .title_bottom("Footer");5152let paragraph = Paragraph::new("Content here")53 .block(block);5455frame.render_widget(paragraph, area);56```5758### Pattern 2: List with Selection5960```rust61use ratatui::widgets::{Block, List, ListItem, ListState};62use ratatui::style::{Style, Stylize};6364let items: Vec<ListItem> = vec![65 ListItem::new("Item 1"),66 ListItem::new("Item 2"),67 ListItem::new("Item 3"),68];6970let list = List::new(items)71 .block(Block::bordered().title("List"))72 .highlight_style(Style::new().reversed())73 .highlight_symbol("> ");7475let mut state = ListState::default();76state.select(Some(0));7778frame.render_stateful_widget(list, area, &mut state);79```8081### Pattern 3: Table with Selection8283```rust84use ratatui::widgets::{Block, Cell, Row, Table, TableState};85use ratatui::style::Stylize;86use ratatui::layout::Constraint;8788let rows = vec![89 Row::new(vec![Cell::from("Alice"), Cell::from("25")]),90 Row::new(vec![Cell::from("Bob"), Cell::from("30")]),91];9293let table = Table::new(rows, [Constraint::Percentage(70), Constraint::Percentage(30)])94 .block(Block::bordered().title("Users"))95 .header(Row::new(vec!["Name", "Age"]).bold())96 .highlight_style(Style::new().reversed());9798let mut state = TableState::default();99state.select(Some(0));100101frame.render_stateful_widget(table, area, &mut state);102```103104### Pattern 4: Tabs105106```rust107use ratatui::widgets::{Block, Tabs};108use ratatui::style::Stylize;109110let tabs = Tabs::new(vec!["Tab 1", "Tab 2", "Tab 3"])111 .block(Block::bordered())112 .select(0)113 .highlight_style(Style::new().bold().yellow());114115frame.render_widget(tabs, area);116```117118### Pattern 5: Gauge/Progress119120```rust121use ratatui::widgets::{Block, Gauge};122use ratatui::style::{Color, Style};123124let gauge = Gauge::default()125 .block(Block::bordered().title("Progress"))126 .gauge_style(Style::new().fg(Color::Green))127 .percent(75)128 .label("75%");129130frame.render_widget(gauge, area);131```132133## API Reference Table134135| Widget | Key Methods | State Type |136|--------|-------------|------------|137| `Block` | `bordered()`, `title()`, `padding()` | None |138| `Paragraph` | `new()`, `block()`, `wrap()`, `scroll()` | None |139| `List` | `new()`, `highlight_style()`, `highlight_symbol()` | `ListState` |140| `Table` | `new()`, `header()`, `widths()`, `highlight_style()` | `TableState` |141| `Tabs` | `new()`, `select()`, `highlight_style()` | None |142| `Gauge` | `percent()`, `ratio()`, `label()` | None |143| `LineGauge` | `ratio()`, `line_set()` | None |144| `Scrollbar` | `orientation()`, `thumb_symbol()` | `ScrollbarState` |145| `Sparkline` | `data()`, `max()`, `bar_set()` | None |146| `Chart` | `datasets()`, `x_axis()`, `y_axis()` | None |147| `BarChart` | `data()`, `bar_width()`, `bar_gap()` | None |148| `Canvas` | `paint()`, `marker()`, `x_bounds()`, `y_bounds()` | None |149| `Clear` | (none) | None |150151## When Writing Code1521531. Wrap content widgets with `Block` for borders and titles1542. Use `ListState::default().select(Some(0))` to start with first item selected1553. Navigate stateful widgets by modifying state, not widget1564. Use `Clear` before rendering popups to erase underlying content1575. Implement `Widget for &MyWidget` for reusable custom widgets158159## When Answering Questions1601611. Widgets are consumed when rendered (use references for reuse)1622. Stateful widgets require external state management1633. Selection uses `Option<usize>` - `None` means nothing selected1644. Most widgets accept `Into<Text>` for content1655. Block is a container widget, not standalone content