6 releases (breaking)
Uses new Rust 2024
| 0.6.0 | Mar 30, 2026 |
|---|---|
| 0.5.0 | Mar 27, 2026 |
| 0.4.0 | Mar 26, 2026 |
| 0.3.0 | Mar 26, 2026 |
| 0.1.0 | Mar 24, 2026 |
#227 in Hardware support
185KB
4K
SLoC
ratatui-cheese
Bubbletea-inspired widgets for Ratatui. Bringing the ergonomics of Charm's Bubbles to the Rust TUI ecosystem.
Usage
Add to your Cargo.toml:
[dependencies]
ratatui-cheese = "0.6"
Widgets
Spinner
Animated spinner with 12 preset types matching Charmbracelet's Bubbles — Line, Dot, MiniDot, Jump, Pulse, Points, Globe, Moon, Monkey, Meter, Hamburger, Ellipsis.
Usage
use std::time::Instant;
use ratatui_cheese::spinner::{Spinner, SpinnerState, SpinnerType};
use ratatui::style::{Color, Style};
let spinner = Spinner::default()
.style(Style::default().fg(Color::Blue));
let mut state = SpinnerState::new(SpinnerType::Dot);
// In your event loop — pass elapsed time, state handles frame timing:
let now = Instant::now();
state.tick(now - last_tick);
last_tick = now;
// In your draw function:
frame.render_stateful_widget(&spinner, area, &mut state);
See it in action (a direct port of the Bubbletea spinners example):
cargo run --example spinners
Help
Keyboard shortcut help view with short (single-line) and full (multi-column) modes, matching Charmbracelet's Bubbles help component.
Usage
use ratatui_cheese::help::{Binding, Help};
let help = Help::default()
.bindings(vec![Binding::new("?", "help"), Binding::new("q", "quit")])
.binding_groups(vec![
vec![Binding::new("?", "help"), Binding::new("q", "quit")],
])
.show_all(true);
// In your draw function:
frame.render_widget(&help, area);
See it in action (a direct port of the Bubbletea help example):
cargo run --example help
Tree
Expandable parent/child tree list with one-level depth. Supports right-aligned counts, text truncation, vertical scrolling, and three display modes (simple, explicit count, parent fallback). Themeable via Palette.
Usage
use ratatui_cheese::tree::{Tree, TreeGroup, TreeItem, TreeState, TreeStyles};
use ratatui_cheese::theme::Palette;
let tree = Tree::default()
.groups(vec![
TreeGroup::new(TreeItem::new("Documents").count(87))
.children(vec![
TreeItem::new("Architecture Decision Records"),
TreeItem::new("Team Onboarding Guide"),
]),
TreeGroup::new(TreeItem::new("Bookmarks").count(31)),
])
.styles(TreeStyles::from_palette(&Palette::dark()));
let mut state = TreeState::new(2);
// Navigation:
// state.select_next(&groups); // move down
// state.toggle_selected(); // expand/collapse
// state.expand_all(); // open everything
// In your draw function:
// frame.render_stateful_widget(&tree, area, &mut state);
cargo run --example tree
Paginator
Page indicator widget with dot (•••••) and arabic (2/10) display modes. Tracks page state and provides helpers for slicing item collections. Ported from Charmbracelet's Bubbles paginator.
Usage
use ratatui_cheese::paginator::{Paginator, PaginatorState, PaginatorMode, PaginatorStyles};
use ratatui_cheese::theme::Palette;
let paginator = Paginator::default()
.mode(PaginatorMode::Dots)
.styles(PaginatorStyles::from_palette(&Palette::dark()));
let mut state = PaginatorState::new(100, 10); // 100 items, 10 per page
// Navigation:
// state.next_page();
// state.prev_page();
// Slice your items for the current page:
// let (start, end) = state.get_slice_bounds(items.len());
// let page_items = &items[start..end];
// In your draw function:
// frame.render_stateful_widget(&paginator, area, &mut state);
cargo run --example paginator
List
Paginated list with item delegation. Each item implements the ListItem trait to control its own height and rendering. Supports custom headers via the ListHeader trait, configurable selection indicators, item spacing, and palette-based theming. Uses the Paginator widget internally.
Usage
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::prelude::*;
use ratatui_cheese::list::{DefaultHeader, List, ListItem, ListItemContext, ListState};
use ratatui_cheese::theme::Palette;
struct Item(String);
impl ListItem for Item {
fn height(&self) -> u16 { 1 }
fn render(&self, area: Rect, buf: &mut Buffer, ctx: &ListItemContext) {
let p = &ctx.palette;
let style = if ctx.selected {
Style::default().fg(p.primary)
} else {
Style::default().fg(p.foreground)
};
buf.set_string(area.x, area.y, &self.0, style);
}
}
let items = vec![Item("Apple".into()), Item("Banana".into())];
let header = DefaultHeader::new("Fruits").show_count(true);
let list = List::new(&items)
.header(&header)
.palette(Palette::charm());
let mut state = ListState::new(items.len());
// Navigation:
// state.select_next(items.len(), false);
// state.select_prev(items.len(), false);
// state.next_page(items.len());
// state.prev_page(items.len());
// In your draw function:
// frame.render_stateful_widget(&list, area, &mut state);
cargo run --example list
Fieldset
Container widget with decorated horizontal rule lines. Renders top and bottom lines with optional title text and a repeating fill character (slash, dash, dot, double, thick, star, or custom). Supports independent left/center/right alignment for top and bottom titles.
Usage
use ratatui::layout::Alignment;
use ratatui_cheese::fieldset::{Fieldset, FieldsetFill, FieldsetStyles};
use ratatui_cheese::theme::Palette;
let fieldset = Fieldset::new()
.title("Section Title")
.title_bottom("End")
.top_alignment(Alignment::Left)
.bottom_alignment(Alignment::Center)
.fill(FieldsetFill::Slash)
.styles(FieldsetStyles::from_palette(&Palette::charm()));
// Get the inner area for content:
// let inner = fieldset.inner(area);
// frame.render_widget(&fieldset, area);
// render children into `inner`
cargo run --example fieldset
License
MIT
Dependencies
~7MB
~118K SLoC