Skip to content
cccskills
FreePublished on GitHub

ratatui

Use when building terminal user interfaces in Rust with the ratatui crate - layout system, widget usage, input/event handling, app state architecture, TUI testing, or migrating between ratatui 0.29 and 0.30

The English summary is being prepared. Showing the original description.

See how to install

Files included (6)

  • SKILL.md9.8 KB
  • references/architecture.md8.6 KB
  • references/ecosystem.md8.6 KB
  • references/recipes.md7.5 KB
  • references/testing.md1.3 KB
  • references/widgets.md10.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Ratatui

Rust terminal UI framework for building interactive command-line applications.

Overview

Ratatui provides widgets, layout systems, event handling, and rendering for TUI apps.

Key Features:

  • Multiple layout systems (blocks, flex, horizontal, vertical)
  • Built-in widgets (buttons, checkboxes, tables, charts)
  • Event-driven input handling with keyboard and mouse support
  • Multiple backends (crossterm, termion, termwiz)
  • no_std support for embedded targets

Installation

[dependencies]
ratatui = "0.30.1"

Feature Flags

ratatui = { version = "0.30.1", default-features = false, features = [
    "crossterm_0_28",  # Crossterm backend
    "layout-cache",    # Layout caching (default enabled)
    "palette",         # HSLuv color support
    "anstyle",         # anstyle conversions
] }

MSRV: 1.88.0 (v0.30.1)

Quick Start

use ratatui::{
    backend::CrosstermBackend,
    layout::{Constraint, Direction, Layout},
    style::{Color, Style},
    widgets::{Block, Borders, Paragraph},
    Frame, Terminal,
};
use std::io;

fn main() -> io::Result<()> {
    let backend = CrosstermBackend::new(io::stdout());
    let mut terminal = Terminal::new(backend)?;

    loop {
        terminal.draw(|f| {
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .constraints([Constraint::Length(3), Constraint::Min(0)])
                .split(f.area());

            let title = Paragraph::new("Hello, Ratatui!")
                .block(Block::bordered().title("Welcome"))
                .style(Style::default().fg(Color::Cyan));
            f.render_widget(title, chunks[0]);

            let instructions = Paragraph::new("Press 'q' to quit")
                .block(Block::bordered().title("Instructions"));
            f.render_widget(instructions, chunks[1]);
        })?;

        break;  // Add your event handling here
    }

    Ok(())
}

Layout System

Constraint Types

use ratatui::layout::{Constraint, Direction, Layout};

let chunks = Layout::default()
    .direction(Direction::Horizontal)
    .constraints([
        Constraint::Percentage(30),  // 30% of area
        Constraint::Length(50),      // 50 characters
        Constraint::Min(10),         // At least 10
        Constraint::Ratio(1, 4),     // 1/4 of remaining
    ])
    .split(area);

Flex Modes

use ratatui::layout::Flex;

// Center alignment
let chunks = Layout::default()
    .direction(Direction::Horizontal)
    .flex(Flex::Center)
    .constraints([Constraint::Length(20)])
    .split(area);

// SpaceEvenly - equal spacing including edges (v0.30+)
let chunks = Layout::default()
    .flex(Flex::SpaceEvenly)
    .constraints([Constraint::Length(20), Constraint::Length(20)])
    .split(area);

// SpaceAround - middle spacers twice the size of edges (v0.30+)
let chunks = Layout::default()
    .flex(Flex::SpaceAround)
    .constraints([Constraint::Length(20), Constraint::Length(20)])
    .split(area);

Overlapping Layouts

use ratatui::layout::Spacing;

// Overlap layouts by -1 spacing (useful for border overlap)
let chunks = Layout::default()
    .spacing(Spacing::Overlap)
    .constraints([Constraint::Length(3), Constraint::Length(3)])
    .split(area);

Ergonomic Rect Methods (v0.30+)

use ratatui::layout::Rect;

let centered = area.centered();                    // Both dimensions
let centered_h = area.centered_horizontally();
let centered_v = area.centered_vertically();
let outer = area.outer(Offset::new(1, 0));         // 1 cell to the right

// Split with compile-time array
let [left, right] = area.layout::<2>(Direction::Horizontal, &constraints);

Nested Layouts

let chunks = Layout::default()
    .direction(Direction::Vertical)
    .constraints([Constraint::Length(3), Constraint::Min(0)])
    .split(area);

let sub_chunks = Layout::default()
    .direction(Direction::Horizontal)
    .constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
    .split(chunks[1]);

Widgets

See references/widgets.md for detailed widget recipes.

WidgetWhen to UseReference
ParagraphText display with styling/wrappingwidgets.md#paragraph
BlockFraming and titling other widgetswidgets.md#block
ButtonClickable buttons with pressed statewidgets.md#button
CheckboxBoolean toggle with custom symbolswidgets.md#checkbox
ListSelectable item listswidgets.md#list
TableTabular data with column selectionwidgets.md#table
GaugeProgress percentage displaywidgets.md#gauge
SparklineCompact data visualizationwidgets.md#sparkline
ChartMulti-dataset plots with axeswidgets.md#chart
CanvasCustom drawing with markerswidgets.md#canvas
CalendarDate display with Chronowidgets.md#calendar
FillPaint area with symbolwidgets.md#fill

Input Handling

Event Handling

use ratatui::event::{Event, EventHandler, KeyCode, KeyModifiers};

if let Some(Event::Key(key)) = handle_events(&mut handler) {
    match key.code {
        KeyCode::Char('q') => break,
        KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => break,
        KeyCode::Down | KeyCode::Char('j') => move_next(),
        KeyCode::Up | KeyCode::Char('k') => move_previous(),
        _ => {}
    }
}

Mouse Support

use ratatui::event::{Event, MouseEventKind};

if let Some(Event::Mouse(mouse)) = handle_events(&mut handler) {
    match mouse.kind {
        MouseEventKind::LeftClick => {
            // Handle click at mouse.column, mouse.row
        }
        MouseEventKind::ScrollDown => {
            // Handle scroll
        }
        _ => {}
    }
}

// Enable mouse capture
crossterm::execute!(stderr(), EnableMouseCapture)?;

State Management

See references/architecture.md for MVU/Flux patterns.

use ratatui::widgets::ListState;

struct AppState {
    items: Vec<String>,
    selected: usize,
    list_state: ListState,
}

impl AppState {
    fn new(items: Vec<String>) -> Self {
        let mut list_state = ListState::default();
        list_state.select(Some(0));
        Self { items, selected: 0, list_state }
    }

    fn next(&mut self) {
        if let Some(selected) = self.list_state.selected {
            let next = (selected + 1) % self.items.len();
            self.list_state.select(Some(next));
            self.selected = next;
        }
    }
}

Styling

use ratatui::style::{Color, Modifier, Style, Stylize};

let style = Style::default()
    .fg(Color::White)
    .bg(Color::Black)
    .add_modifier(Modifier::BOLD);

// Stylize trait (v0.30+)
let style = Style::new().blue().on_black().bold();
let styled: Text = "hello".yellow();

Color Types

Color::Reset        // Terminal default
Color::Red          // Basic terminal colors
Color::Rgb(255, 128, 0)  // True color
Color::Indexed(42)  // 256-color palette
Color::from_hsluv(Hsluv::new(0.0, 100.0, 50.0))  // HSLuv (requires "palette" feature)

Best Practices & Performance

Separate State from View

Keep state management separate from rendering logic. Use MVU pattern for predictable data flow.

Minimize Redraws

if app.state_changed {
    terminal.draw(|f| render_app(f, &app))?;
    app.state_changed = false;
}

Use Clear for Popups

Prevent content bleeding by clearing popup areas:

use ratatui::widgets::Clear;
Clear.render(popup_area, buf);

Handle Resize

use ratatui::event::Event;

if let Ok(Event::Resize(width, height)) = term.read_event() {
    term.resize(width, height)?;
}

Panic Recovery

std::panic::set_hook(Box::new(|_| {
    let _ = ratatui::restore();
}));

Breaking Changes: v0.29 → v0.30

ChangeMigration
Block::title() removedUse Block::new().title(Line::from("foo"))
block::Title deprecatedUse Line directly (removal in v0.31)
Style no longer implements StyledUse Style::new().blue() then widget.style(style)
Table::highlight_style() deprecatedUse table.row_highlight_style(...)
Marker is #[non_exhaustive]Use Marker::Custom('x') for custom markers
Backend requires Error typeAdd associated Error type to your backend
Rect::area() returns u32Update type expectations

Migration Example

// Old
Block::new().title("foo")

// New
Block::new().title(Line::from("foo").centered())

// Old
table.highlight_style(Style::default().fg(Color::Yellow))

// New
table.row_highlight_style(Style::default().fg(Color::Yellow))

Deep Dives

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Use when building Python async HTTP services or clients with aiohttp - web server routing, middleware, WebSocket, SSE, streaming, client sessions, pytest-aiohttp testing, or troubleshooting SSL and timeout issues

The English summary is being prepared. Showing the original description.

CodeAtCode/oss-ai-skills24Updated Oct 9, 2026

Use when doing structural code search and rewriting - ast-grep linting, refactoring, multi-language patterns

The English summary is being prepared. Showing the original description.

CodeAtCode/oss-ai-skills24Updated Oct 9, 2026

Use when building GBA games with the BPCore Lua engine - entity, sprite and tilemap functions, SRAM save and load, link cable multiplayer protocol, camera and scrolling, or optimization patterns

The English summary is being prepared. Showing the original description.

CodeAtCode/oss-ai-skills24Updated Oct 9, 2026

celery

Free

Use when running background tasks with Celery - worker and broker configuration (Redis, RabbitMQ), task routing by name vs queue, chains/groups/chords, retry patterns (autoretry_for, retry_backoff), acks_late semantics, failure detection, and monitoring with Flower

The English summary is being prepared. Showing the original description.

CodeAtCode/oss-ai-skills24Updated Oct 9, 2026

django

Free

Use when building Django applications - security hardening, authentication and permissions, ORM optimization, PostgreSQL features, Django 6.0, migrations, testing, and ecosystem libraries

The English summary is being prepared. Showing the original description.

CodeAtCode/oss-ai-skills24Updated Oct 9, 2026

Use when customizing Django Admin - save_formset, get_search_results, formsets, queryset optimization, db_index, custom URLs

The English summary is being prepared. Showing the original description.

CodeAtCode/oss-ai-skills24Updated Oct 9, 2026

See all skills by CodeAtCode

Report a problem with this skill