tui-breadcrumb 0.1.0

A customizable, interactive hierarchical breadcrumb navigation widget for Ratatui.
Documentation

๐Ÿž tui-breadcrumb

A customizable, responsive, and interactive hierarchical navigation trail widget for Ratatui.

Crates.io Documentation Downloads CI Codecov Release License Ratatui

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ๐Ÿ“ Home โฏ ๐Ÿ“‚ Projects โฏ ๐Ÿ“ฆ ratatui โ–พ โฏ ๐Ÿ“„ sparkline.rs                     โ”‚
โ”‚    โ–ฒ          โ–ฒ             โ–ฒ                โ–ฒ                              โ”‚
โ”‚  Root      Parent      Ancestor with       Active                           โ”‚
โ”‚  Segment   Segment     Dropdown            Item                             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ“– Overview

Terminal user interfacesโ€”such as file managers, cloud resource consoles, database browsers, and nested configuration screensโ€”frequently require breadcrumb navigation paths. Without a dedicated widget, developers often manually assemble Line and Span collections and write custom string truncations that break on Unicode characters or fail to support mouse interaction.

tui-breadcrumb solves this by providing:

  • Built-in Separator Presets: Slash (/), Chevron (โฏ), Angle (โ€บ), Arrow (โ†’), Pipe (|), Backslash (\\), Double Angle (ยป), or custom glyphs.
  • Smart Responsive Truncation: Intelligently fits breadcrumbs to any terminal column width using strategies like Middle, Start, ShortenNames, End, or None.
  • Full Interactivity (BreadcrumbState): Keyboard focus navigation (Left/Right arrows) and pixel-accurate mouse hit testing for segment clicks and ancestor dropdown triggers (โ–พ).
  • Filesystem Path Integration: Seamless conversions from standard std::path::Path.
  • Zero Panics & Unicode Safe: Built with unicode-width to prevent column drift across emojis, CJK characters, and combining glyphs.

๐Ÿ“ฆ Installation

Add tui-breadcrumb to your Cargo.toml:

cargo add tui-breadcrumb

Or manually:

[dependencies]
tui-breadcrumb = "0.1.0"
ratatui = "0.30"

๐Ÿš€ Quick Start

1. Simple Stateless Breadcrumb

use ratatui::prelude::*;
use tui_breadcrumb::{Breadcrumb, BreadcrumbSeparator, TruncateStrategy};

fn render_trail(frame: &mut Frame, area: Rect) {
    let widget = Breadcrumb::new(["Home", "Projects", "ratatui", "src", "sparkline.rs"])
        .separator(BreadcrumbSeparator::chevron())
        .strategy(TruncateStrategy::middle())
        .item_style(Style::default().fg(Color::Gray))
        .active_style(Style::default().fg(Color::Yellow).bold());

    frame.render_widget(widget, area);
}

2. Interactive Stateful Breadcrumb (Keyboard & Mouse Support)

use ratatui::prelude::*;
use ratatui::crossterm::event::{Event, KeyCode, MouseEventKind, MouseButton};
use tui_breadcrumb::{Breadcrumb, BreadcrumbItem, BreadcrumbSeparator, BreadcrumbState, TruncateStrategy};

struct App {
    state: BreadcrumbState,
    items: Vec<BreadcrumbItem<'static>>,
}

impl App {
    fn new() -> Self {
        let mut state = BreadcrumbState::default();
        state.select(Some(2)); // Focus 3rd segment

        let items = vec![
            BreadcrumbItem::new("Home"),
            BreadcrumbItem::with_dropdown("Projects"),
            BreadcrumbItem::with_dropdown("ratatui"),
            BreadcrumbItem::new("src"),
            BreadcrumbItem::new("main.rs"),
        ];

        Self { state, items }
    }

    fn handle_event(&mut self, event: Event) {
        match event {
            Event::Key(key) => match key.code {
                KeyCode::Left => self.state.select_previous(self.items.len()),
                KeyCode::Right => self.state.select_next(self.items.len()),
                KeyCode::Home => self.state.select_first(),
                KeyCode::End => self.state.select_last(self.items.len()),
                _ => {}
            },
            Event::Mouse(mouse) if mouse.kind == MouseEventKind::Down(MouseButton::Left) => {
                let (col, row) = (mouse.column, mouse.row);
                // Check if user clicked an ancestor dropdown arrow (โ–พ)
                if let Some(drop_idx) = self.state.dropdown_at(col, row) {
                    println!("Clicked dropdown for item index {}", drop_idx);
                }
                // Check if user clicked a crumb label
                else if let Some(item_idx) = self.state.item_at(col, row) {
                    self.state.select(Some(item_idx));
                }
            }
            _ => {}
        }
    }

    fn render(&mut self, frame: &mut Frame, area: Rect) {
        let widget = Breadcrumb::new(self.items.clone())
            .separator(BreadcrumbSeparator::chevron())
            .strategy(TruncateStrategy::middle())
            .selected_style(Style::default().bg(Color::DarkGray).fg(Color::White).bold());

        frame.render_stateful_widget(widget, area, &mut self.state);
    }
}

๐Ÿ“ Truncation Strategies

When a breadcrumb trail exceeds available terminal width, [TruncateStrategy] determines how segments are condensed:

Strategy Output Pattern Description
Middle (Default) Home โฏ ... โฏ src โฏ sparkline.rs Preserves root context and active leaf; collapses intermediate segments into ....
Start ... โฏ tui-breadcrumb โฏ src โฏ sparkline.rs Preserves deepest active leaf and immediate parents; collapses leftmost ancestors.
ShortenNames H โฏ P โฏ ratatui โฏ src โฏ sparkline.rs Progressively abbreviates ancestor segment labels to single characters before collapsing.
End Home โฏ Projects โฏ ratatui โฏ ... Left-to-right priority; preserves root ancestors and collapses leaf segments.
None Home โฏ Projects โฏ ratatui โฏ src Strict clipping at the boundary without ellipsis substitution.
// Examples of configuring strategies:
let middle = TruncateStrategy::middle_with(1, 2, "...");
let start = TruncateStrategy::start_with(2, "โ€ฆ");
let shorten = TruncateStrategy::shorten_names_with(1, 2, "...");

๐ŸŽจ Separator Presets

BreadcrumbSeparator includes built-in glyph presets with configurable spacing and styling:

Preset Constructor Symbol Visual Preview (Spacing = 1)
BreadcrumbSeparator::chevron() โฏ Home โฏ Projects โฏ ratatui
BreadcrumbSeparator::slash() / Home / Projects / ratatui
BreadcrumbSeparator::angle() โ€บ Home โ€บ Projects โ€บ ratatui
BreadcrumbSeparator::arrow() โ†’ Home โ†’ Projects โ†’ ratatui
BreadcrumbSeparator::pipe() | Home | Projects | ratatui
BreadcrumbSeparator::backslash() \\ Home \\ Projects \\ ratatui
BreadcrumbSeparator::double_angle() ยป Home ยป Projects ยป ratatui
BreadcrumbSeparator::custom(sym) * Home * Projects * ratatui
// Customize separator styling and spacing:
let sep = BreadcrumbSeparator::chevron()
    .spacing(1)
    .style(Style::default().fg(Color::DarkGray));

๐Ÿ“‚ Filesystem Path Integration

Easily initialize a breadcrumb navigation trail directly from a [std::path::Path]:

use std::path::Path;
use tui_breadcrumb::Breadcrumb;

let path = Path::new("/var/log/nginx/access.log");
let widget = Breadcrumb::from_path(path);

๐ŸŽฎ Examples & Demos

The examples/ directory includes multiple practical applications showcasing different integration patterns:

Example Command Description
Interactive Demo cargo run --example demo Full-featured demo with keyboard navigation, strategy switching, and mouse clicks.
Minimal Quickstart cargo run --example simple Minimal zero-config ~25 line getting started example.
File Explorer cargo run --example file_explorer Two-pane directory browser with live from_path updates and click-to-jump.
Custom Styling Gallery cargo run --example custom_styling Side-by-side gallery of Powerline pills, CI badges, Retro amber/green, and Minimal dots.
Dropdown Popovers cargo run --example dropdown_menus Deep resource hierarchy with floating sibling branch selection modals.
Responsive Truncation Lab cargo run --example responsive_resize Interactive width caliper and live comparator across all 5 truncation strategies.

Example Highlights:

  • Interactive Showcase (demo.rs): Navigate crumbs with โ†/โ†’/h/l, cycle separators with Tab, toggle strategies with 1โ€“5, and click โ–พ dropdown triggers.
  • Minimal Quickstart (simple.rs): Minimal template for quick integration into existing projects.
  • Filesystem Navigation (file_explorer.rs): Browse directories with Enter/Backspace, or click any parent breadcrumb segment to jump immediately to that directory.
  • Theming & Powerline Gallery (custom_styling.rs): Inspect 4 visual themes: Powerline pill styling (๎‚ฐ), CI/CD status badges ([โœ” Build] โฏ [โšก Tests]), Retro green phosphor (//), and Minimal dots (โ€ข).
  • Deep Hierarchies & Dropdowns (dropdown_menus.rs): Click โ–พ on any resource level to open a floating modal of alternate sibling branches.
  • Truncation & Width Caliper (responsive_resize.rs): Adjust container width in real time ([/] or arrow keys) to observe and compare all 5 truncation strategies on emoji-rich paths.

๐Ÿงช Testing & Verification

tui-breadcrumb includes a comprehensive verification suite:

# Run unit tests
cargo test --lib

# Run documentation tests
cargo test --doc

# Run property-based invariant tests (QuickCheck)
cargo test --test property_test

# Run visual regression snapshot tests (Insta)
cargo test --test snapshots

# Run linter and formatting checks
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --all -- --check

๐Ÿค Contributing

Contributions are welcome! Please check out CONTRIBUTING.md for guidelines on development setup, running tests, code standards, and submitting pull requests.


๐Ÿ“„ License

This project is dual-licensed under:

You may choose either license at your option.