Ratatouille garnished with little purple flowers and basil leaves served in a bowl with a gear shaped edge

ratatui-garnish Garnish your Ratatui Widgets

basil sprig

ratatui-garnish is a powerful composition system for Ratatui widgets, allowing you to change de rendering of any widget with garnishes like borders, titles, shadows, padding, and styles in a flexible, type-safe way. Layer multiple garnishes in any order, apply them at runtime, and modify them without altering the underlying widget. With zero-cost abstractions and no trait objects, ratatui-garnish ensures performance and type safety.

Want a margin outside a border? Add Padding before a border. Need multiple titles or a shadow effect? Just garnish! Writing custom widgets but dreading the boilerplate for styling or borders? Use ratatui-garnish with any widget implementing Widget or StatefulWidget.

Features

Installation

Add ratatui-garnish to your Cargo.toml:

[dependencies]
ratatui-garnish = "0.1.0"
ratatui = "0.29"

Usage

Import the GarnishableWidget trait to add the garnish method to any Ratatui widget:

use ratatui::{style::{Color, Style}, text::Text, widgets::Padding};
use ratatui_garnish::{border::RoundedBorder, title::{Title, Above}, GarnishableWidget};

// Create a text widget with multiple decorations
let widget = Text::raw("Hello, World!\nTasty TUIs from Ratatui")
    .garnish(RoundedBorder::default())           // Add a rounded border
    .garnish(Title::<Above>::raw("My App"))      // Add a title above
    .garnish(Style::default().bg(Color::Blue))   // Set a background color
    .garnish(Padding::uniform(1));               // Add padding inside

Garnishes are applied in the order they are added, with before_render effects (e.g., styles, shadows) applied first, followed by the widget, and then after_render effects (e.g., titles over borders).

Complex Example

Combine multiple garnishes for a polished UI:

use ratatui::{style::{Color, Style, Modifier}, text::Line, widgets::Padding};
use ratatui_garnish::{border::DoubleBorder, shadow::Shadow, title::{Title, Top, Bottom}, GarnishableWidget};

let widget = Line::raw("Important Message")
    .garnish(Padding::uniform(2))                       // Margin outside
    .garnish(Style::default().bg(Color::DarkGray))      // Background color
    .garnish(Title::<Top>::styled("⚠ WARNING ⚠",        // Styled title
        Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)).margin(1))
    .garnish(Title::<Bottom>::raw("Status: Active").right_aligned().margin(1))
    .garnish(DoubleBorder::default());                   // Double border

Reusing Garnishes

Use the Garnishes vec to apply the same garnishes to multiple widgets:

use ratatui::{style::{Color, Style, Modifier}, text::Line, widgets::Padding};
use ratatui_garnish::{border::DoubleBorder, title::{Title, Top}, garnishes, GarnishableWidget};

let garnishes = garnishes![
    Style::default().fg(Color::Blue),
    DoubleBorder::default(),
    Padding::uniform(2),
    Style::default().fg(Color::White),
];

let mut widget1 = Line::raw("First Widget")
    .garnish(Title::<Top>::styled("First", Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)).margin(1));
widget1.extend_from_slice(&garnishes);

let mut widget2 = Line::raw("Second Widget")
    .garnish(Title::<Top>::styled("Second", Style::default().fg(Color::Green).add_modifier(Modifier::BOLD)).margin(1));
widget2.extend(garnishes);

Accessing Garnishes

Treat a GarnishedWidget like a Vec to inspect or modify its garnishes:

let widget = Line::raw("Test")
    .garnish(Style::default().bg(Color::Blue))
    .garnish(Padding::uniform(1));
assert!(widget[0].is_style());
assert_eq!(widget.first_padding(), Some(&Padding::uniform(1)));

Available Garnishes

Borders

Titles

Shadows

Built-in Ratatui Support

Performance

Compatibility

ratatui-garnish integrates seamlessly with Ratatui widgets implementing Widget or StatefulWidget following Ratatui’s conventions.

Contributing

This is the first release of ratatui-garnish, and more garnishes are planned! Contributions are welcome.

License

Licensed under the MIT License. See the LICENSE file for details.

Acknowledgements

Built with love for the Rust and Ratatui communities. Inspired by the need for flexible, reusable widget modification.