Data Widgets
List
Selectable list of items with optional headers, spacers, prefixes, and scrollbar.
| Prop | Type | Description |
|---|---|---|
items | impl Iterator<Item = ListItem> | List items |
selected | usize | Selected index |
scroll_keys | bool | Enable keyboard scroll keys |
scroll_wheel | bool | Enable mouse wheel |
scrollbar | bool | Show scrollbar |
scrollbar_config | ScrollbarConfig | Full scrollbar configuration (variant, gap, thumb, thumb styles) |
show_scroll_indicators | bool | Show top/bottom overflow indicators |
scroll_indicator_style | Style | Overflow indicator style |
border | bool | Draw border |
title | String | Border title |
padding | impl Into<Padding> | Inner padding |
empty_text | String | Text when list is empty |
empty_text_style | Style | Empty text style |
active_style | Style | Style for rows where ListItem::active(true) |
active_symbol | Option<impl Into<Arc<str>>> | Prefix symbol for active rows |
active_symbol_position | ListSymbolPosition | Render active symbol on the left or immediately after the label |
active_symbol_style | Style | Style for active symbol |
selection_symbol | Option<String> | Prefix for selected item (e.g. "> ") |
selection_style | Style | Selected item style |
selection_full_width | bool | Extend selection to full width |
item_horizontal_padding | impl Into<Padding> | Left/right padding for normal rows (top/bottom ignored) |
header_horizontal_padding | impl Into<Padding> | Left/right padding for header rows (top/bottom ignored) |
focusable | bool | Accept focus |
width | Length | Width |
height | Length | Height |
on_select | Callback<ListEvent> | Selection changed |
on_item_click | Callback<ListEvent> | Row clicked with mouse |
on_activate | Callback<ListEvent> | Item activated (Enter/double-click) |
on_scroll_to | Callback<usize> | Scroll position changed |
ListItem Types
ListItem::new("Normal item") // Selectable row
ListItem::header("Section Title") // Non-selectable header row
ListItem::spacer() // Non-selectable blank row
ListItem::new("Service").active(true) // Marks row as active
ListItem::role(ListItemRole::Header) // Explicit role
// Multi-line rows
ListItem::new("build")
.line(ListItemLine::new("target/debug/build.log").selection_left(false))
// Prefix helpers
ListItem::new("Item").numbered(1)
ListItem::new("Bullet").bulleted('•')
ListItem::new("Label")
.prefix("> ")
.prefix_style(Style::new().fg(Color::Cyan))
// Symbol can be rendered on a non-primary line (useful for "description above")
ListItem::new("description")
.line(ListItemLine::new("label"))
.symbol_line(1)Keyboard/mouse selection and activation skip non-selectable rows (Header/Spacer).
ListItem::line(...) adds extra visual lines under the primary line. Selection, activation, and callbacks still use the item index (not visual line index).
ListItem::prefix(...) renders a prefix before the primary label and automatically indents extra lines to match the label start. Use .extra_line_indent(...) to override that alignment when needed.
selection_symbol(e.g."> ") is prepended to the selected item. Unselected items are padded with spaces to maintain alignment. Include a trailing space in the symbol if needed.
Active row rendering is independent from selection. Use
active_symbol_position(ListSymbolPosition::Right)to render the active marker after the label instead of in the left symbol column. When using the right position, include any desired separator in the symbol itself (for example" ✓").
item_horizontal_paddingandheader_horizontal_paddingacceptPadding, but onlyleft/rightare applied inList.
Pointer vs keyboard row hover: For
ListandTable, whenitem_hover_styleis non-empty, changingselectedfrom the keyboard or from component logic (not a row click) stops using the mouse position for per-row hover until the pointer moves. Widget-level hover and row clicks behave as usual.Treeuses an innerListwith the sameitem_hover_styleprop, so it follows the same rules automatically.
List::new()
.items(self.files.iter().map(|f| ListItem::new(f.name.clone())))
.selected(self.selected)
.scrollbar(true)
.selection_symbol(Some("> ".to_string()))
.selection_style(Style::new().fg(Color::Cyan).bold())
.on_select(ctx.link().callback(|e| Msg::FileSelected(e.index)))
.on_activate(ctx.link().callback(|e| Msg::FileOpened(e.index)))Table
Structured data with rows, columns, and optional scrollbar.
| Prop | Type | Description |
|---|---|---|
header | TableRow | Column header row |
rows | Vec<TableRow> | Data rows |
widths | Vec<ColumnWidth> | Column widths |
selected | Option<usize> | Selected row index |
column_spacing | u16 | Space between columns |
scroll_keys | bool | Keyboard scroll |
scroll_wheel | bool | Mouse wheel |
scrollbar | bool | Scrollbar |
scrollbar_config | ScrollbarConfig | Full scrollbar configuration (variant, gap, thumb, thumb styles) |
show_scroll_indicators | bool | Overflow indicators |
scroll_indicator_style | Style | Indicator style |
selection_symbol | Option<String> | Selected row prefix |
selection_style | Style | Selected row style |
header_style | Style | Header row style |
row_style | Style | Default row style |
alternating_row_style | Style | Style applied to odd rows for zebra striping |
row_style_full_width | bool | Extend row hover/selection/zebra style across full row width |
focusable | bool | Accept focus |
width | Length | Width |
height | Length | Height |
on_select | Callback<TableEvent> | Row selection changed |
on_activate | Callback<TableEvent> | Row activated |
on_scroll_to | Callback<usize> | Scroll position |
Column Widths
ColumnWidth::Fixed(10) // Fixed cell width
ColumnWidth::Fill(1) // Proportional fill
ColumnWidth::Min(5) // Minimum width, fills remainingRow Sizing
TableRow::new(vec!["col1", "col2"])
.height(2) // Fixed height
.auto_height() // Height = max line count of cells
.bottom_margin(1) // Spacing below rowHeatmap Cells
TableCell::heat_fg(value, &gradient, GradientRange::new(0.0, 100.0)) // Color fg by value
TableCell::heat_bg(value, &gradient, GradientRange::new(0.0, 100.0)) // Color bg by valueInspector Patterns
Table::inspector(true) // Enable inspector presets
// Row helpers
TableRow::key_value("Name", "Alice")
TableRow::section("Personal Info")
TableRow::separator()
// Hierarchy
TableRow::new(cells)
.depth(2)
.disclosure(TableDisclosureState::Expanded)Inspector styling hooks: inspector_key_style, inspector_value_style, inspector_section_style, inspector_separator_style, inspector_indent_size, inspector_disclosure_symbols, inspector_separator_char.
Row semantics: TableRowRole::{Normal, Section, Separator}.
Table::new()
.header(TableRow::new(vec!["ID", "Name", "Status"]))
.rows(self.data.iter().map(|d| {
TableRow::new(vec![d.id.to_string(), d.name.clone(), d.status.clone()])
}).collect())
.widths(vec![ColumnWidth::Fixed(5), ColumnWidth::Fill(1), ColumnWidth::Fixed(10)])
.alternating_row_style(Style::new().bg(Color::indexed(236)))
.row_style_full_width(true)
.selected(Some(self.selected))
.selection_style(Style::new().fg(Color::Cyan))
.on_select(ctx.link().callback(|e| Msg::RowSelected(e.index)))Tree
Hierarchical tree view with expand/collapse.
| Prop | Type | Description |
|---|---|---|
root | TreeNode | Constructor - root node |
gap | u16 | Vertical gap between items |
icon_gap | u16 | Gap between icon and label |
show_icons | bool | Show expand/collapse icons |
expanded_icon | String | Icon for expanded nodes |
collapsed_icon | String | Icon for collapsed nodes |
leaf_icon | String | Icon for leaf nodes |
icon_style | Style | Icon style |
indent_style | Style | Indent guide style |
indent_guide_style | Style | Vertical indent guide |
indent_gradient | ColorGradient | Gradient for indent depth |
style | Style | Base style |
hover_style | Style | Hover style |
item_hover_style | Style | Individual item hover |
selection_style | Style | Selected item style |
selection_symbol | String | Selected item prefix |
selection_symbol_style | Style | Prefix style |
scrollbar | bool | Scrollbar |
scrollbar_config | ScrollbarConfig | Full scrollbar configuration (variant, gap, thumb, thumb styles) |
scroll_keys | bool | Keyboard scroll |
scroll_wheel | bool | Mouse wheel |
empty_text | String | Text when tree is empty |
empty_text_style | Style | Empty text style |
focusable | bool | Accept focus |
activate_on_click | bool | Single-click activates |
keymap | TreeKeymap | Keyboard expand/collapse mapping |
focus_policy | FocusPolicy | Accordion behavior |
width | Length | Width |
height | Length | Height |
on_select | Callback<TreeEvent> | Node selected |
on_toggle | Callback<TreeToggleEvent> | Node expanded/collapsed |
Tree is implemented with an inner List (flattened visible rows). Per-row item_hover_style and pointer vs keyboard row hover behavior match List - see the callout under List.
Building Nodes
TreeNode::new("parent")
.expanded(true)
.child(
TreeNode::new("child-1")
)
.child(
TreeNode::new("child-2")
.child(TreeNode::new("grandchild"))
)
// With styled ListItem
TreeNode::new(ListItem::from_spans(vec![
Span::new("file.rs").fg(Color::Cyan),
Span::new(" [modified]").fg(Color::Yellow),
]))Events
// TreeEvent { index: usize, path: Vec<usize> }
// TreeToggleEvent { index: usize, path: Vec<usize>, expanded: bool }
.on_select(ctx.link().callback(|e: TreeEvent| Msg::NodeSelected(e.path)))
.on_toggle(ctx.link().callback(|e: TreeToggleEvent| Msg::NodeToggled(e.path, e.expanded)))Keymap: TreeKeymap supports expand/collapse via Left/Right, h/l, Space (toggle).
FileTree
Lazy-loading filesystem explorer built on Tree.
| Prop | Type | Description |
|---|---|---|
root | impl Into<String> | Constructor - root directory path |
show_hidden | bool | Show hidden files (. prefix) |
max_entries_per_dir | usize | Cap entries per directory |
git_status | bool | Show git status badges (default: true) |
git_refresh_token | u64 | Token to trigger deterministic git refresh |
directory_icon | String | Directory icon |
file_icon | String | File icon |
symlink_icon | String | Symlink icon |
other_icon | String | Other entry icon |
explorer | bool | Show fuzzy search input |
explorer_placeholder | String | Search input placeholder |
explorer_prefix | String | Search input prefix |
explorer_input_border | bool | Search input border |
explorer_match_style | Style | Fuzzy match highlight |
explorer_divider | bool | Show divider between search and tree |
on_select | Callback<FileTreeEvent> | File/dir selected |
on_toggle | Callback<FileTreeToggleEvent> | Directory expanded/collapsed |
Plus all Tree styling/scrolling props, including scrollbar_config.
Behavior:
- Directories load on demand in a background command on first expand.
- Fuzzy matching respects
.gitignore/.ignorerules. - Auto-expands ancestor directories to reveal search matches.
- Restores pre-search expansion state when query clears.
- Queries containing file extensions (e.g.
layout.rs) prioritize filename matches.
FileTree::new("/home/user/projects")
.git_status(true)
.show_hidden(false)
.explorer(true)
.explorer_placeholder("Filter files...")
.on_select(ctx.link().callback(|e: FileTreeEvent| Msg::FileSelected(e.path)))Events
// FileTreeEvent { path: PathBuf, kind: FileTreeEntryKind }
// FileTreeToggleEvent { path: PathBuf, kind: FileTreeEntryKind, expanded: bool }LogView
High-throughput log list with level highlighting and fuzzy filtering.
| Prop | Type | Description |
|---|---|---|
buffer | Arc<LogBuffer> | Bounded ring buffer of log entries |
filter_mode | MatchMode | Fuzzy, Substring, Exact |
case_sensitive | bool | Case-sensitive filtering |
auto_follow | bool | Auto-scroll to newest entry |
paused | bool | Pause log streaming display |
trace_style | Style | TRACE level style |
debug_style | Style | DEBUG level style |
info_style | Style | INFO level style |
warn_style | Style | WARN level style |
error_style | Style | ERROR level style |
on_select | Callback<LogViewEvent> | Entry selected |
on_activate | Callback<LogViewEvent> | Entry activated |
Plus standard list/scroll styling props, including scrollbar_config.
let buffer = Arc::new(LogBuffer::new(10_000)); // 10k entry ring buffer
// In a background thread: buffer.push(LogEntry { level, message });
LogView::new(buffer.clone())
.filter_mode(MatchMode::Fuzzy)
.auto_follow(true)
.info_style(Style::new().fg(Color::Green))
.error_style(Style::new().fg(Color::Red).bold())Events
// LogViewEvent { visible_index: usize, source_index: usize, entry: LogEntry }