A customizable, responsive, and interactive hierarchical navigation trail widget for Ratatui.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ Home โฏ ๐ Projects โฏ ๐ฆ ratatui โพ โฏ ๐ sparkline.rs โ
โ โฒ โฒ โฒ โฒ โ
โ Root Parent Ancestor with Active โ
โ Segment Segment Dropdown Item โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
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, orNone. - Full Interactivity (
BreadcrumbState): Keyboard focus navigation (Left/Rightarrows) 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-widthto prevent column drift across emojis, CJK characters, and combining glyphs.
Add tui-breadcrumb to your Cargo.toml:
cargo add tui-breadcrumbOr manually:
[dependencies]
tui-breadcrumb = "0.1.0"
ratatui = "0.30"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);
}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);
}
}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, "...");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));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);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. |
- Interactive Showcase (
demo.rs): Navigate crumbs withโ/โ/h/l, cycle separators withTab, toggle strategies with1โ5, and clickโพdropdown triggers. - Minimal Quickstart (
simple.rs): Minimal template for quick integration into existing projects. - Filesystem Navigation (
file_explorer.rs): Browse directories withEnter/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.
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 -- --checkContributions are welcome! Please check out CONTRIBUTING.md for guidelines on development setup, running tests, code standards, and submitting pull requests.
This project is dual-licensed under:
- MIT License (LICENSE-MIT or https://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
You may choose either license at your option.