Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Big text and menus

Big text rendered in box-drawing or pixel fonts, plus vertical menus with animated selection styles and a grouped settings list.

BigText

Renders text at 3 or 5 rows per line in one of four fonts. Use it for headings, splash screens and menu items.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer) {
BigText::new("TUILE")
    .font(BigFont::Block5)
    .gradient(&[Rgb(230, 60, 60), Rgb(255, 160, 40)])
    .render(area, buf);
}
fn main() {}

Fonts

Four fonts available. Lowercase letters are uppercased. Unsupported characters fall back to ?.

Box3 (default): 3-row heavy box-drawing font. Solid strokes in every terminal font. Supports A-Z, 0-9, and .,:-_+!?/[]<>. Most letters are 3 cells wide. Example rendering:

┏━┓┳ ┳┏━┓
┣━┫┣━┫┃┫ 
┻ ┻┻ ┻┗━┛

Block5: 5-row figlet-style font with painted solid cells (background paint, not foreground glyphs). Supports A-Z, 0-9, and .,:-_+!/[]<>. Most letters are 5 cells wide, numbers 4 or 5 wide. Example rendering:

 ### 
#   #
#####
#   #
#   #

Half3: 3-row font using half-blocks ▀▄ for partial cells with painted solids. Same character set as Block5. Pixel fonts already carry a 1-cell gap after each glyph. Most letters are 5 cells wide plus gap. Example rendering:

 ▀▀▀ 
█▀▀█
█  █

Thin3: 3-row light box-drawing font (─│╭╮╰╯) for elegant headings. Same character set as Box3. Most letters are 3 cells wide. Example rendering:

╭─╮┬ ┬╭─╮
├─┤├─┤│ 
╯ ╯╯ ╯╰─╯

The pixel fonts (Block5, Half3) include a 1-cell trailing gap in their width calculation. Line fonts (Box3, Thin3) add a 1-cell gap between glyphs by default.

Builder options

MethodEffect
font(BigFont)Choose the font (default Box3)
color(Rgb)Flat color for the text
gradient(&[Rgb])Left-to-right color stops across the text
bg(Rgb)Background behind glyph strokes (default th.background); pass the panel color when drawing on a card
spacing(u16)Cells between glyphs (default: the font’s natural gap, 1 for line fonts, 0 for pixel fonts)
align(Alignment)Left, Center, or Right (default Left)
bold(bool)Apply bold modifier (default false)
theme(&Theme)Override the default theme

BigText::width_of(text, font, spacing) returns the cell width a string takes in a given font.

BigTitle

A title with optional subtitle and rule.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer) {
BigTitle::new("WELCOME")
    .subtitle("Select an option to begin")
    .font(BigFont::Block5)
    .gradient(&[Rgb(100, 200, 255), Rgb(180, 100, 255)])
    .rule(true)
    .render(area, buf);
}
fn main() {}

The title is center-aligned. If a subtitle is set, it appears 2 rows below the title. If rule(true), a horizontal rule is drawn after the subtitle (or title if no subtitle).

MethodEffect
subtitle(&str)Optional subtitle below the title
font(BigFont)Choose the font (default Block5)
gradient(&[Rgb])Left-to-right color stops across the title
rule(bool)Draw a horizontal rule after the text (default false)
theme(&Theme)Override the default theme

height() returns the total rows the title occupies with its current settings.

BigMenu

A vertical menu of big-font items with many rendering styles.

Basic usage

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer) {
let mut state = BigMenuState::default();
BigMenu::new(&["START", "OPTIONS", "QUIT"])
    .style(BigMenuStyle::Arrows)
    .focused(true)
    .render(area, buf, &mut state);
if let Some(i) = state.take_activated() {
    // user pressed Enter or clicked item i
}
}
fn main() {}

The menu can be built from simple strings or from BigMenuItem structs that carry a description, icon, disabled flag, and hotkey.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer) {
let mut state = BigMenuState::default();
let items = [
    BigMenuItem::new("NEW GAME").icon("▸").hotkey('n'),
    BigMenuItem::new("LOAD").icon("◧").disabled(true),
    BigMenuItem::new("QUIT").icon("◆").hotkey('q'),
];
BigMenu::items(&items)
    .style(BigMenuStyle::Cards)
    .focused(true)
    .render(area, buf, &mut state);
}
fn main() {}

State

BigMenuState owns the selection cursor, mouse hit boxes, and animation tweens.

FieldPurpose
selectedIndex of the currently selected item
hitsMouse hit boxes (read-only, updated on render)
MethodPurpose
take_activated()Returns Some(index) when an item was chosen with Enter/Space/click since the last call
animating(now)True if an animation is active (for Underline style tween)

Keys and mouse

KeyAction
Up, kMove selection up
Down, jMove selection down
LeftMove selection up (wraps to last)
RightMove selection down (wraps to first)
HomeSelect first item
EndSelect last item
Enter, SpaceActivate selected item

Mouse hover changes the selection. Click activates the item. Wheel scrolls through items.

Styles

Ten rendering styles, each with different selection markers, animations, and layout.

Plain (default): Selected item in accent or gradient, others muted.

Arrows: Arrow markers ▸ and ◂ flanking the selected item with animated bounce.

Boxed: Round border frame around the selected item.

Underline: Underline under the selected item that tweens between items when selection changes.

Glow: Selected item bright with a horizontal gradient that sweeps across it, unselected items dimmed.

Shadow: Drop shadow (offset right and down), selected item raised in accent.

Bracket: Big bracket glyphs [ and ] around the selected item.

Horizontal: Items laid in one row separated by a gap. Left and Right navigate, Up and Down wrap.

Cards: Each item in its own card with label and description (requires BigMenuItem with description).

Retro: Pulse-blink selected item, > prefix cursor, all caps, monochrome.

Builder options

MethodEffect
style(BigMenuStyle)Choose the rendering style (default Plain)
gap(u16)Blank rows between items (default 1)
focused(bool)Draw focus indicator (default false)
align(Alignment)Left, Center, or Right (default Center)
color(Rgb)Color of the selected item (default th.accent)
selected_gradient(&[Rgb])Gradient across the selected item instead of flat color
font(BigFont)Choose the font (default Box3)
now(Instant)Pass the current time for animations
theme(&Theme)Override the default theme

height() returns the total rows the menu needs to show all items. width() returns the widest item including the style’s side chrome.

When an item is too wide for the available area, the menu first tries the label with letters touching (spacing 0), then truncates to the longest prefix that fits.

OptionList

A settings menu with grouped rows, in-place value cycling, and a group index for a sidebar. The shape of omp’s settings screen.

Structure

An OptionListState owns a Vec<OptionGroup>. Each group has a title and a Vec<OptionItem>. Each item has a stable key, a visible label, a value, and an optional hint.

Values can be Bool, Choice (one of N strings), Int (with min/max/step), Text (read-only, the app edits it elsewhere), or Action (a command). Left/Right, h/l and Space cycle the value at the cursor and report the key through take_changed; Enter reports it through take_activated instead, so the app can open a dropdown or a field for it. Text and Action never cycle.

Each row can carry trail cells - where the value came from, when a change takes effect - which are drawn as aligned columns after the value, and dim(true) for a row showing something the user did not choose, which mutes the value and the trail. value_rect(row) gives back the cell the value was drawn in, so an editor can be placed over it.

extern crate tuile;
extern crate ratatui_core;
use tuile::prelude::*;

fn demo(area: Rect, buf: &mut Buffer) {
let mut state = OptionListState::new(vec![
    OptionGroup::new("Theme", vec![
        OptionItem::choice("theme", "Dark Theme", &["titanium", "nord", "dracula"], 0),
        OptionItem::bool("colorblind", "Color-Blind Mode", false)
            .trail(["default", "next session"])
            .dim(true),
    ]),
    OptionGroup::new("Display", vec![
        OptionItem::int("fps", "Frame rate", 60, 15, 120, 15),
    ]),
]);
OptionList::new().focused(true).render(area, buf, &mut state);
if let Some(key) = state.take_changed() {
    let theme = state.choice("theme");
}
if let Some(key) = state.take_activated() {
    // open an editor for `key`
}
}
fn main() {}

State methods

MethodPurpose
take_changed()Returns the key of the row whose value changed (or whose action fired) since the last call
get(&str)Returns a reference to the value for a key
get_mut(&str)Returns a mutable reference to the value for a key
bool(&str)Returns Some(bool) if the key is a Bool value
choice(&str)Returns the selected option text of a Choice row
int(&str)Returns Some(i64) if the key is an Int value
group_index()Index of the group the cursor is in (for a sidebar)
jump_to_group(usize)Move the cursor to the first row of a group

Keys and mouse

KeyAction
Up, kMove cursor up
Down, jMove cursor down
HomeJump to first row
EndJump to last row
Left, hCycle value backward (Bool toggles, Choice moves to previous option, Int decrements by step)
Right, lCycle value forward
EnterCycle value forward for Bool/Choice/Int, report changed for Text/Action

Mouse hover changes the cursor. Click on a row selects it and cycles its value forward. Wheel scrolls through rows.

The cursor is a flat index over all items in group order. Group headers are visible but not selectable.

Widget options

MethodEffect
focused(bool)Draw focus indicator (default false)
value_column(u16)Column where values start (default: widest label + 4)
cursor_glyph(&str)Glyph shown to the left of the cursor row (default ❯)
theme(&Theme)Override the default theme

The widget renders group headers in muted text, then each row as cursor label value hint. The hint (if present) appears after the value in muted text only when the cursor is on that row.

The scrollbar appears when the list is taller than the area. keep_visible keeps the cursor row visible.