Input Widgets
Button
Interactive button.
| Prop | Type | Description |
|---|---|---|
label | impl Into<String> | Constructor - button text |
variant | ButtonVariant | Visual variant |
style | Style | Idle style |
hover_style | Style | Hover style |
focus_style | Style | Focus style |
border_style | BorderStyle | Idle border |
hover_border_style | BorderStyle | Hover border |
focus_border_style | BorderStyle | Focus border |
align | Align | Label alignment |
padding | impl Into<Padding> | Inner padding |
icon | Span | Icon span (prepended to label) |
icon_style | Style | Icon style |
icon_gap | u16 | Space between icon and label |
shortcut | String | Keyboard shortcut label |
shortcut_bindings | KeyBindings | Keyboard shortcut alternatives (displayed canonically) |
shortcut_style | Style | Shortcut style |
shortcut_gap | u16 | Space between label and shortcut |
width | Length | Width |
height | Length | Height |
focusable | bool | Whether button accepts focus |
disabled | bool | Disable button |
disabled_style | Style | Style when disabled |
on_click | Callback<MouseEvent> | Click / Enter callback |
on_key | KeyHandler | Key handler |
Button::new("Save")
.style(Style::new().fg(Color::White).bg(Color::Blue))
.shortcut_bindings("ctrl+s, super+s".parse().unwrap())
.focus_style(Style::new().fg(Color::White).bg(Color::DarkBlue).bold())
.on_click(ctx.link().callback(|_| Msg::Save))DragSource
Wrapper that turns a single child into a generic drag source.
| Prop | Type | Description |
|---|---|---|
child | impl Into<Element> | Wrapped draggable content |
on_drag_start | Fn(DragStartEvent) -> Option<Box<dyn DragPayload>> | Drag-start handler that returns payload; None aborts drag |
on_drag_cancel | Callback<DragCancelEvent> | Fired when drag is canceled or dropped on invalid target |
on_drag_started | Callback<DragStartedEvent> | Fired once when the drag activates (after the movement threshold); includes payload |
drag_group | impl Into<Arc<str>> | Optional compatibility group |
clear_drag_group | () | Remove group restriction |
preview | DragPreview | Label text near pointer, SourceSnapshot (layout slot collapses per drag_slot; float preview copies cells), or None |
preview_label | impl Into<Arc<str>> | Convenience for DragPreview::Label |
preview_snapshot | () | Convenience for DragPreview::SourceSnapshot |
no_preview | () | Convenience for DragPreview::None |
drag_slot | DragSlot | Collapse (0 main-axis cells) or Specified(Length) using the same Length rules as stack children (Auto, Px, Percent, Flex). In VStack/HStack the stack axis applies; elsewhere use drag_slot_axis. |
drag_slot_collapse | () | Same as drag_slot(DragSlot::Collapse) |
drag_slot_length | Length | Same as drag_slot(DragSlot::Specified(len)) |
drag_slot_axis | DragSlotAxis | Vertical or Horizontal: which axis Fixed/Collapse apply to when measured outside a stack (default: vertical) |
dragging_style | Style | Overlay while dragging: first-frame tint, reserved slot fill when using SourceSnapshot, and label/none preview modes |
preview_max_width | Option<u16> | Max width of the floating SourceSnapshot preview (None → DEFAULT_PREVIEW_MAX_WIDTH) |
preview_max_height | Option<u16> | Max height of the floating preview (None → DEFAULT_PREVIEW_MAX_HEIGHT) |
preview_max_size | (Option<u16>, Option<u16>) | Set both max dimensions |
threshold | u16 | Pointer movement threshold before drag starts (default: 3) |
enabled | bool | Enable/disable drag behavior |
DragSource::new()
.child(Text::new("main.rs"))
.on_drag_start(|ev| {
let _ = (ev.x, ev.y);
Some(Box::new(String::from("main.rs")) as Box<dyn DragPayload>)
})
.preview_label("main.rs")
.threshold(3)DropTarget
Wrapper that marks a single child as a generic drop zone.
| Prop | Type | Description |
|---|---|---|
child | impl Into<Element> | Wrapped drop-zone content |
on_drag_over | Callback<DragOverEvent> | Fired when compatible payload hovers target |
on_drag_leave | Callback<DragLeaveEvent> | Fired when active drag leaves target |
on_drop | Callback<DropEvent> | Fired on successful drop |
accept_group | impl Into<Arc<str>> | Restrict accepted source group |
clear_accept_group | () | Accept all groups (None) |
can_accept | PayloadAcceptFn | Optional payload predicate |
can_accept_with | Fn(&dyn DragPayload) -> bool | Closure form of payload predicate |
clear_can_accept | () | Remove payload predicate |
highlight | DropHighlight | None, Fill, Placeholder (bordered frame), or Overlay (tint after children) |
highlight_style | Style | Style for Fill / Placeholder / Overlay |
highlight_fill | Style | highlight(DropHighlight::Fill) + highlight_style |
highlight_placeholder | Style | highlight(DropHighlight::Placeholder) + highlight_style |
highlight_overlay | Style | highlight(DropHighlight::Overlay) + highlight_style |
drop_slot | DropSlot | Child (render child normally, default) or SourcePreview (replace child with the dragged card's snapshot; cursor float is suppressed) |
drop_slot_source_preview | () | Shorthand for drop_slot(DropSlot::SourcePreview) |
enabled | bool | Enable/disable drop behavior |
on_drag_over is emitted on every pointer move while a compatible drag hovers this target (not only on enter). Use DragOverEvent::local_y (offset from the drop target’s top edge) with a row-height estimate to place a single insertion line. DropEvent::local_y uses the same convention.
DropTarget::new()
.child(Text::new("Drop here"))
.accept_group("files")
.can_accept_with(|payload| payload.downcast_ref::<String>().is_some())
.on_drop(ctx.link().callback(|ev| Msg::Dropped(ev.payload)))Hyperlink
Clickable text link built on top of Button with link-style defaults.
| Prop | Type | Description |
|---|---|---|
label | impl Into<Arc<str>> | Constructor - visible link text |
href | Arc<str> | Optional URL metadata emitted in callbacks |
style | Style | Idle style |
hover_style | Style | Hover style |
focus_style | Style | Focus style |
disabled_style | Style | Style when disabled |
visited_style | Style | Style overlay when visited: true |
align | Align | Label alignment |
padding | impl Into<Padding> | Inner padding |
width | Length | Width |
height | Length | Height |
focusable | bool | Whether link accepts focus |
disabled | bool | Disable interaction |
visited | bool | Mark link as visited |
on_activate | Callback<HyperlinkEvent> | Emits on click, Enter, and Space |
on_key | KeyHandler | Fallback key handler |
Hyperlink::new("Open docs")
.href("https://example.com/docs")
.visited(self.docs_opened)
.visited_style(Style::new().fg(Color::Magenta).underline())
.on_activate(ctx.link().callback(Msg::OpenLink))HyperlinkEvent contains:
label: Arc<str>href: Option<Arc<str>>
Open the destination explicitly from component logic:
if let Some(url) = ev.href.as_deref() {
let _ = tui_lipan::utils::open_url(url);
}Input
Single-line text input field.
| Prop | Type | Description |
|---|---|---|
value | impl Into<String> | Constructor - current text value |
cursor | usize | Byte cursor position |
anchor | Option<usize> | Selection anchor (for text selection) |
caret_shape | CaretShape | Cursor shape - default: Block (only set when you want Bar or Underline) |
caret_color | Option<Color> | OSC 12 cursor color (terminal support required) |
style | Style | Idle style |
focus_style | Style | Focused style |
placeholder | String | Placeholder when empty |
mask | Option<char> | Masking character (e.g., '*' for passwords) |
read_only | bool | Allow selection but block keyboard input |
focusable | bool | Whether input accepts focus; mouse selection and Ctrl+C copy still work when false |
width | Length | Width |
height | Length | Height |
on_change | Callback<String> | Emits new value on each keystroke |
on_edit | Callback<TextEditEvent> | Emits structured edit events |
key_interceptor | KeyHandler | Runs before text insertion |
Input::new(self.query.clone())
.placeholder("Search...")
.style(Style::new().fg(Color::White))
.focus_style(Style::new().fg(Color::White).bg(Color::indexed(237)))
.on_change(ctx.link().callback(Msg::QueryChanged))
caret_coloruses OSC 12. SetTUI_LIPAN_OSC12=0to disable if your terminal doesn't support it.
Undo/Redo: Ctrl+Z, Ctrl+Shift+Z, Ctrl+Y (also handles raw control codes).
TextArea
Multi-line text editor.
| Prop | Type | Description |
|---|---|---|
value | impl Into<String> | Constructor - current text value |
cursor | usize | Byte cursor position |
anchor | Option<usize> | Selection anchor |
caret_shape | CaretShape | Cursor shape - default: Block (only set when you want Bar or Underline) |
caret_color | Option<Color> | OSC 12 cursor color |
line_numbers | bool | Show line number gutter |
gutter_inset | u16 | Empty cells before the gutter / line numbers |
wrap | bool | Word wrap (default: true) |
max_width | Option<u16> | Max line width before forced wrap |
scroll_offset | Option<usize> | Controlled vertical scroll |
scroll_wheel | bool | Mouse wheel scrolling |
scrollbar | bool | Vertical scrollbar |
scrollbar_config | ScrollbarConfig | Full scrollbar configuration (variant, gap, thumb, thumb styles) |
h_scrollbar | bool | Horizontal scrollbar (only when wrap: false) |
style | Style | Idle style |
focus_style | Style | Focused style |
placeholder | String | Placeholder when empty |
placeholder_style | Style | Placeholder style |
focus_placeholder_style | Style | Placeholder when focused |
read_only | bool | Allow selection but block keyboard input |
triple_click_mode | TripleClickSelectionMode | Triple-click selects a line or paragraph |
newline_binding | TextAreaNewlineBinding | Enter key behavior |
on_change | Callback<TextAreaEvent> | Emits value, cursor, anchor on each edit |
on_edit | Callback<TextEditEvent> | Structured edit events |
sentinels | Vec<TextAreaSentinel> | Custom inline PUA tokens (SENTINEL_BASE + index in value) |
on_sentinels_change | Callback<Vec<TextAreaSentinel>> | Fires when the list is pruned (e.g. user deleted a token) |
on_sentinel_event | Callback<Vec<SentinelEvent>> | Lifecycle events with stable ids (e.g. Deleted) |
key_interceptor | KeyHandler | Runs before text editing |
on_scroll | Callback<ScrollEvent> | Scroll event with metrics |
on_scroll_to | Callback<usize> | Target scroll offset |
color_strategy | Box<dyn TextAreaColorStrategy> | Syntax highlighting strategy |
language | String | Language hint for syntax highlighting; use language_from_path(path) to resolve from a file path |
theme | String | Syntax theme name |
images | Vec<ImageContent> | Attached images |
on_images_change | Callback<Vec<ImageContent>> | Images list updated |
image_mode | TextAreaImageMode | Inline or Attachment |
image_placeholder | String | Placeholder text for inline images |
image_placeholder_style | Style | Inline image placeholder style |
on_image_paste | Callback<ImageContent> | Legacy: image pasted via Ctrl+V |
width | Length | Width |
height | Length | Height |
focusable | bool | Participate in focus traversal; mouse selection and Ctrl+C copy still work when false |
TextArea::new(self.text.clone())
.line_numbers(true)
.wrap(false)
.h_scrollbar(true)
.on_change(ctx.link().callback(Msg::TextChanged))Custom inline sentinels (extmarks)
Styled atomic tokens in the buffer use a separate PUA range from inline images: SENTINEL_BASE (U+F000). Entry i in sentinels maps to the single character U+F000 + i in value. One backspace/delete removes the whole codepoint; the framework prunes the parallel sentinels list and can emit SentinelEvent batches (see docs/enums.md and docs/events.md).
| Type / API | Role |
|---|---|
TextAreaSentinel | Label, styles, optional type-erased payload, optional SentinelId (or assign via insert_sentinel) |
insert_sentinel(value, cursor, sentinels, sentinel) | Insert at cursor; assigns SentinelId::next() when id is unset |
TextAreaSnapshot | capture / apply / diff for in-memory stash–restore |
Prefer on_sentinel_event for cleanup keyed by stable id; keep on_sentinels_change if you only need the pruned list.
Example: examples/text_area_sentinels.rs
Syntax Highlighting (requires feature syntax-syntect)
TextArea::new(code.clone())
.with_syntax("rust", "base16-ocean.dark")
// With background colors
.with_syntax_bg("rust", "one-dark")
// Auto-detect language from file path (extension/filename matching, no I/O)
TextArea::new(code.clone())
.language_from_path("src/main.rs") // resolves to "Rust"
.with_syntax_strategy(SyntectStrategy::default(), "Rust", "base16-ocean.dark")
// Or use the free function to get the language string yourself
if let Some(lang) = tui_lipan::language_from_path(&file_path) {
area = area.language(lang);
}
// Custom theme from file
.with_syntax_custom_theme_from_file("rust", "MyTheme", "/path/to/theme.tmTheme")Built-in themes: Catppuccin Frappe, Catppuccin Latte, Catppuccin Macchiato, Catppuccin Mocha, Dracula, InspiredGitHub, Monokai Extended, One Dark (Atom), Solarized (dark), Solarized (light), base16-eighties.dark, base16-mocha.dark, base16-ocean.dark, base16-ocean.light.
SyntectStrategy::use_background(true) - apply syntax theme backgrounds (default: false).
When a TextArea, DocumentView, or DiffView uses SyntectStrategy, the app theme can now gently recolor token categories via Theme::syntax(...) while still using the selected syntect theme for tokenization and base styling.
Image Modes (requires feature image)
Inline mode (images embedded as Unicode PUA sentinels in text value):
TextArea::new(self.input.clone())
.image_mode(TextAreaImageMode::Inline)
.images(self.images.clone())
.on_images_change(ctx.link().callback(Msg::ImagesChanged))
.image_placeholder("[Img]")
.image_placeholder_style(Style::new().fg(Color::Magenta).bold())Sentinel characters (U+E000…) represent images in the text value. Cursor movement and deletion work naturally. Use IMAGE_SENTINEL_BASE to construct sentinel chars manually if needed.
Attachment mode (images in separate list, text value unchanged):
VStack::new()
.gap(0)
.child(
if !self.images.is_empty() {
DraggableTabBar::new()
.tabs(self.images.iter().enumerate().map(|(i, _)| {
DraggableTab::new(format!("Image {}", i + 1)).closeable(true)
}))
.active(usize::MAX)
.close_symbol("x")
.draggable(false)
.focusable(false)
.on_close(ctx.link().callback(Msg::RemoveImage))
.into()
} else { Element::empty() }
)
.child(
TextArea::new(self.input.clone())
.image_mode(TextAreaImageMode::Attachment)
.images(self.images.clone())
.on_images_change(ctx.link().callback(Msg::ImagesChanged))
)Image pasting is opt-in: only active when on_images_change or on_image_paste is set. Without these, Ctrl+V pastes text only.
DiffView (requires feature diff-view)
Diff viewer with pluggable backends:
DiffViewBackend::TextArea(default) - supports editable modeDiffViewBackend::DocumentView- read-only review + selection optimized
Backend selection rules:
- Explicit
.backend(...)always wins. - If backend is not set explicitly, calling
.document_view(...)switches toDocumentView. - If backend is not set explicitly, calling
.text_area(...)switches toTextArea. - Outer
DiffViewsizing inherits the active backend'swidth/heightunless you override it with.width(...)/.height(...). - Pane borders are rendered by internal
Framewrappers, not by innerTextArea/DocumentViewborders.
Line numbers in DiffView are source-mapped (git-style), not visual-row counters:
- Split left pane shows original (
before) line numbers. - Split right pane shows modified (
after) line numbers. - Unified mode uses original numbers for removed lines, and modified numbers for added/context lines.
| Prop | Type | Description |
|---|---|---|
before | String | Constructor (first arg) - original text |
after | String | Constructor (second arg) - modified text |
mode | DiffViewMode | Split (default) or Unified |
backend | DiffViewBackend | TextArea (default) or DocumentView |
editable | bool | Enable editing (TextArea backend only) |
width | Length | Override outer diff view width (otherwise inherit active backend width) |
height | Length | Override outer diff view height (otherwise inherit active backend height) |
wrap | bool | Apply wrapping to both backends |
line_numbers | bool | Toggle line numbers in both backends |
min_line_number_width | u8 | Minimum gutter digits in both backends |
gutter_inset | u16 | Empty cells before the gutter / line numbers in both backends |
border | bool | Toggle outer border around the whole DiffView |
panels_border | bool | Toggle per-pane wrapper borders |
scrollbar | bool | Toggle vertical scrollbar in both backends |
h_scrollbar | bool | Toggle horizontal scrollbar in both backends |
focusable | bool | Toggle focusability in both backends |
single_scrollbar | bool | In split mode, show vertical scrollbar only on right pane |
join_frame | bool | Join split-pane wrapper frames (Frame::join_frame) |
vertical_separator | bool | Insert vertical divider between split panes |
vertical_separator_char | char | Character used by split divider |
vertical_separator_style | Style | Style for split divider |
highlight_full_width | bool | Extend changed-line background highlight to full row width |
word_diff | bool | Word-level diff highlighting |
trim_common_indent | bool | Trim the smallest shared leading indent from visible diff lines (default: true) |
show_prefixes | bool | Show +/- prefix symbols |
diff_style | DiffPalette | Added/removed/context-separator/patch-header styles |
neutral_bg | Color | Convenience setter for context/unchanged line background |
base_color_strategy | Box<dyn TextAreaColorStrategy> | Syntax highlighting base strategy |
language | String | Language hint; use language_from_path(path) to resolve from a file path |
theme | String | Syntax theme name |
text_area | TextArea | Pre-configured TextArea for scroll/border/wrap settings |
document_view | DocumentView | Pre-configured DocumentView for scroll/border/wrap settings |
scroll_offset | usize | Controlled scroll offset (applies to rendered pane(s)) |
context_lines | usize | Collapse unchanged regions farther than n lines from any change into a separator line (default: show all) |
show_context_separator | bool | Show/hide the context separator placeholder when collapsing context (default: true) |
context_separator_text | String | Template for context separator text; supports {count}, {line_word}, {direction}, {arrow} |
shared_selection_id | Arc<str> | Cross-widget selection group id (unified: as-is; split: auto-suffixed :left/:right) |
on_scroll | Callback<DiffScrollEvent> | Pane-aware scroll callback (pane + ScrollEvent) |
let diff = DiffView::new(before, after)
.mode(DiffViewMode::Split)
.document_view(DocumentView::new("")) // backend inferred
.height(Length::Auto) // useful for inline/message-style diff blocks
.border(true)
.panels_border(true)
.wrap(true)
.line_numbers(true)
.min_line_number_width(4)
.single_scrollbar(true)
.join_frame(true)
.vertical_separator(true)
.vertical_separator_style(Style::new().dim())
.highlight_full_width(true)
.neutral_bg(Color::rgb(24, 24, 24))
.word_diff(true)
.show_prefixes(true);
By default, `DiffView` derives its added/removed/marker styling from `Theme::diff`.
Use `.diff_style(...)` only when you want per-widget overrides.
`DiffView` also trims shared leading indentation by default so deeply indented code is easier to read inline. Use `.trim_common_indent(false)` when you need the original left margin preserved exactly.
// Efficient: build DiffData once, reuse across renders
let data = DiffData::with_config(before, after, config);
let diff = DiffView::new(before, after).with_diff(data);
// or: DiffView::new(before, after).with_shared_diff(Arc<DiffData>)
// DiffDataConfig fields:
// - word_diff: bool - precompute word-level diff tokens
// - context_lines: Option<usize> - collapse unchanged regions (same as the prop)
// - show_context_separator: bool - insert separator placeholder (default: true)
// - context_separator_text: Arc<str> - template for separator text
// Split scroll sync pattern (controlled):
let mut offset: Option<usize> = None;
let mut diff = DiffView::new(before, after)
.mode(DiffViewMode::Split)
.on_scroll(ctx.link().callback(|ev: DiffScrollEvent| Msg::DiffScrolled(ev)));
if let Some(v) = offset {
diff = diff.scroll_offset(v);
}
// Custom diff colors (lines + markers + line numbers):
let style = DiffPalette {
added: Style::new().bg(Color::rgb(0x14, 0x2F, 0x20)),
removed: Style::new().bg(Color::rgb(0x3B, 0x1E, 0x24)),
context_line_number: Style::new().fg(Color::DarkGray), // fg/bg for unchanged line numbers in gutter
added_marker: Style::new().fg(Color::Green),
removed_marker: Style::new().fg(Color::Red),
added_line_number: Style::new().fg(Color::DarkGray), // fg/bg for added line numbers in gutter
removed_line_number: Style::new().fg(Color::DarkGray), // fg/bg for removed line numbers in gutter
context_separator_style: Style::new().fg(Color::DarkGray).dim(), // style for context-collapse separator lines
patch_header: Style::new().fg(Color::Cyan).bold(), // style for in-band `diff --git ...` metadata lines
..DiffPalette::default()
};
// Context lines - collapse unchanged regions far from changes:
DiffView::new(before, after)
.context_lines(3) // show 3 lines of context around each change
.context_separator_text("{arrow} {count} {line_word} omitted {direction}")
.show_context_separator(false) // omit separator placeholders entirely
.mode(DiffViewMode::Unified);
// Separator lines are excluded from copy operations.
// Both Split and Unified modes support context_lines.
// Default separator text is arrow-based and direction-aware, e.g. "↑ 9 hidden lines above ↑".
// The separator style is themed by default (dimmed muted text); override via DiffPalette::context_separator_style.
// Raw patch metadata lines like `diff --git a/... b/...` stay in the scrollable diff and use DiffPalette::patch_header.
// Auto-detect language from file path (requires feature `syntax-syntect`):
DiffView::new(before, after)
.language_from_path("src/main.rs") // resolves to "Rust", no-op if unknown
.theme("One Dark (Atom)"); // set theme separately; with_syntax() would override the detected languageCheckbox
Toggle widget for boolean values.
| Prop | Type | Description |
|---|---|---|
checked | bool | Constructor - checked state |
state | CheckboxState | Full state (overrides checked) |
indeterminate | bool | Show indeterminate state |
label | String | Label text |
variant | CheckboxVariant | Visual variant |
gap | u16 | Space between box and label |
style | Style | Idle style |
hover_style | Style | Hover style |
focus_style | Style | Focus style |
checked_style | Style | Style when checked |
unchecked_style | Style | Style when unchecked |
indeterminate_style | Style | Style when indeterminate |
label_style | Style | Label style |
padding | impl Into<Padding> | Padding |
disabled | bool | Disable interaction |
disabled_style | Style | Style when disabled |
on_toggle | Callback<bool> | Toggle callback |
on_click | Callback<()> | Click callback |
Radio
Radio button group.
| Prop | Type | Description |
|---|---|---|
options | Vec<Arc<str>> | Constructor - option labels |
selected | Option<usize> | Selected index |
layout | RadioLayout | Vertical or Horizontal |
variant | RadioVariant | Visual variant |
gap | u16 | Space between options |
style | Style | Base style |
checked_style | Style | Selected item style |
unchecked_style | Style | Unselected item style |
hover_style | Style | Hover style |
focus_style | Style | Focus style |
label_style | Style | Label style |
disabled | bool | Disable interaction |
disabled_style | Style | Style when disabled |
on_change | Callback<usize> | Selection changed callback |
Radio::new(vec!["Option A".into(), "Option B".into(), "Option C".into()])
.selected(Some(self.choice))
.layout(RadioLayout::Horizontal)
.on_change(ctx.link().callback(Msg::ChoiceChanged))Select
Dropdown select widget.
| Prop | Type | Description |
|---|---|---|
options | Vec<String> | Available options |
selected | Option<usize> | Selected index |
placeholder | String | Placeholder when nothing selected |
expanded | bool | Controlled expanded state |
width | Length | Width |
disabled | bool | Disable interaction |
on_select | Callback<usize> | Item selected |
on_change | Callback<usize> | Selection changed |
on_toggle | Callback<bool> | Dropdown opened/closed |
button_variant | ButtonVariant | Trigger button variant |
button_style | Style | Button idle style |
button_hover_style | Style | Button hover style |
button_focus_style | Style | Button focus style |
button_disabled_style | Style | Button disabled style |
button_border_style | BorderStyle | Trigger border style (outlined variant) |
button_hover_border_style | BorderStyle | Trigger border style when hovered |
button_focus_border_style | BorderStyle | Trigger border style when focused |
button_open_suffix | String | Trigger suffix while expanded |
button_closed_suffix | String | Trigger suffix while collapsed |
button_suffix_style | Style | Trigger suffix style |
list_title | String | Dropdown title (bordered list) |
list_title_style | Style | Dropdown title style |
list_border | bool | Dropdown list border |
list_border_style | BorderStyle | Dropdown border style |
list_padding | impl Into<Padding> | Dropdown padding |
list_style | Style | Dropdown list style |
list_selection_style | Style | Selected item style |
list_selection_full_width | bool | Extend selection style across full row |
list_selection_symbol | Option<String> | Selection symbol for selected row |
list_selection_symbol_style | Style | Selection symbol style |
list_hover_style | Style | Hover style in list |
list_width | Length | Dropdown width override |
list_height | Length | Dropdown height override |
match_button_width | bool | Force dropdown width to trigger width |
list_scrollbar | bool | Scrollbar in list |
list_scrollbar_config | ScrollbarConfig | Full scrollbar configuration (variant, gap, thumb, thumb styles) |
list_empty_text | String | Dropdown empty text |
list_empty_text_style | Style | Dropdown empty text style |
list_disabled_style | Style | Dropdown disabled style |
ComboBox
Controlled input + dropdown list for searchable selection.
| Prop | Type | Description |
|---|---|---|
items | Vec<Arc<str>> | Source options |
query | Arc<str> | Controlled input value |
placeholder | String | Input placeholder |
open | bool | Controlled dropdown state |
active_index | Option<usize> | Active source index |
selected | Option<usize> | Selected source index fallback |
allow_custom_value | bool | Allow Enter to commit free-form query |
width | Length | Input width |
list_width | Length | Dropdown width override |
list_height | Length | Dropdown height |
match_input_width | bool | Force dropdown width to match input width |
disabled | bool | Disable interaction |
input_hover_style | Style | Input hover style |
input_disabled_style | Style | Input disabled style |
input_hover_border_style | BorderStyle | Input border style while hovered |
input_open_suffix | String | Suffix when dropdown is open |
input_closed_suffix | String | Suffix when dropdown is closed |
input_suffix_style | Style | Input suffix style |
input_focus_suffix_style | Style | Input suffix style when focused |
on_query_change | Callback<Arc<str>> | Input query changed |
on_open_change | Callback<bool> | Request open/close change |
on_active_index_change | Callback<Option<usize>> | Active source index changed |
on_commit | Callback<ComboBoxCommitEvent> | Enter/activate commit event |
ComboBoxCommitEvent contains:
index: Option<usize>value: Arc<str>from_custom_value: bool
Interaction notes:
- With
match_input_width(true), dropdown width follows the rendered trigger/input width.
MultiSelect
Controlled list for selecting multiple items with Space toggle and Enter commit.
| Prop | Type | Description |
|---|---|---|
items | impl Iterator<Item = impl Into<MultiSelectItem>> | Source rows |
active_index | usize | Active source index |
selected_indices | Vec<usize> | Controlled selected source indices |
max_selected | usize | Optional maximum selected rows |
selected_prefix | String | Prefix for selected rows (default: [x]) |
unselected_prefix | String | Prefix for unselected rows (default: [ ]) |
description_style | Style | Style used for item descriptions |
description_placement | MultiSelectDescriptionPlacement | Description placement: Inline, Right, Above, Below |
description_overflow | MultiSelectDescriptionOverflow | Description overflow policy: Truncate or Wrap (Wrap applies to Above/Below) |
description_selection | bool | Whether selection highlight applies to descriptions |
width | Length | Width |
height | Length | Height |
title | String | List title (requires border) |
title_style | Style | List title style |
selection_full_width | bool | Expand selection style across row width |
disabled | bool | Disable interaction |
disabled_style | Style | Style when disabled |
empty_text | String | Text when list is empty |
empty_text_style | Style | Empty-text style |
on_active_index_change | Callback<usize> | Active row changed |
on_toggle | Callback<MultiSelectToggleEvent> | Current row toggled |
on_change | Callback<MultiSelectChangeEvent> | Selected set changed |
on_commit | Callback<MultiSelectCommitEvent> | Enter commit with selected set |
Event payloads:
MultiSelectToggleEvent { index, selected }MultiSelectChangeEvent { selected_indices }MultiSelectCommitEvent { selected_indices }
Interaction notes:
- Space toggles the active_index row.
- Mouse click on a row toggles that row and updates the active row.
- Enter emits
on_commit(mouse click does not commit).
MultiSelectItem supports optional descriptions:
MultiSelectItem::new("Cargo.toml")
.description("Workspace manifest")description_selection(false) only affects Above/Below description lines. For Inline and Right, selection/hover styling still applies to the full row.
description_overflow(MultiSelectDescriptionOverflow::Wrap) affects only Above/Below placement. Inline and Right keep single-row truncation behavior.
HexArea
Hex/ASCII binary data viewer with keyboard cursor navigation.
| Prop | Type | Description |
|---|---|---|
bytes | Arc<[u8]> | Constructor - byte buffer to render |
cursor | usize | Controlled cursor byte index |
anchor | Option<usize> | Optional selection anchor byte index |
read_only | bool | Read-only mode flag |
bytes_per_row | u16 | Number of bytes rendered per row |
show_ascii | bool | Show ASCII preview column |
show_offsets | bool | Show hexadecimal offset gutter |
uppercase_hex | bool | Uppercase (AA) or lowercase (aa) hex output |
scroll_offset | Option<usize> | Controlled row scroll offset |
style | Style | Base style |
hover_style | Style | Hover style |
focus_style | Style | Focus style |
selection_style | Style | Selection style |
cursor_style | Style | Cursor byte style |
pending_edit_style | Style | Background/style for half-entered nibble edits |
border | bool | Draw border |
border_style | BorderStyle | Border style |
padding | impl Into<Padding> | Inner padding |
width | Length | Width |
height | Length | Height |
focusable | bool | Participate in focus traversal |
disabled | bool | Disable interaction |
on_cursor_change | Callback<HexAreaCursorEvent> | Emits on cursor movement (keyboard/mouse) |
on_change | Callback<HexAreaChangeEvent> | Emits updated bytes after edits |
on_edit | Callback<HexAreaEditEvent> | Emits per-edit metadata (replace/insert/delete) |
on_scroll | Callback<ScrollEvent> | Emits desired row offset during navigation/wheel scrolling |
on_key | KeyHandler | Custom key handler fallback |
HexAreaCursorEvent contains:
cursor: usizeanchor: Option<usize>
Interaction notes:
- Hex and ASCII columns are both clickable and map to the same byte index.
- Click-and-drag creates/extends a byte-range selection.
- First typed hex digit clears the cell to
<digit>and enters pending-nibble mode. - Pending-nibble mode highlights the edited cell with
pending_edit_style. Esccancels pending-nibble mode and restores the original byte.
HexAreaEditEvent contains:
index: usizebefore: Option<u8>after: Option<u8>kind: HexAreaEditKind
Edit keys (when read_only(false) and on_change is set):
- Hex digits (
0-9,a-f) replace bytes in two-keystroke nibble mode Insertinserts0x00at cursorDeleteremoves byte at cursorBackspaceremoves byte before cursorCtrl+Zundo,Ctrl+Shift+Z/Ctrl+Yredo
Slider
Numeric selection slider.
| Prop | Type | Description |
|---|---|---|
value | f64 | Constructor - current value |
min | f64 | Minimum value |
max | f64 | Maximum value |
step | f64 | Step increment |
label | String | Label text |
show_value | bool | Show current value |
thumb_symbol | char | Thumb character |
track_symbol | char | Empty track character |
filled_track_symbol | char | Filled track character |
hover_thumb_symbol | char | Thumb on hover |
style | Style | Base style |
filled_track_style | Style | Filled portion style |
filled_track_gradient | ColorGradient | Filled portion gradient |
thumb_style | Style | Thumb style |
thumb_gradient | ColorGradient | Thumb gradient |
focus_style | Style | Focus style |
focus_thumb_style | Style | Thumb when focused |
hover_thumb_style | Style | Thumb on hover |
label_style | Style | Label style |
padding | impl Into<Padding> | Padding |
width | Length | Width |
height | Length | Height |
focusable | bool | Accept focus |
on_change | Callback<f64> | Value changed |
on_click | Callback<f64> | Click / Enter |
DatePicker
Calendar-based date selection.
| Prop | Type | Description |
|---|---|---|
year | i32 | Current year |
month | u32 | Current month (1–12) |
day | Option<u32> | Selected day |
title | String | Calendar title |
show_outside_days | bool | Show days from adjacent months |
border | bool | Draw border |
border_style | BorderStyle | Border appearance |
padding | impl Into<Padding> | Padding |
style | Style | Base style |
header_style | Style | Month/year header style |
weekday_style | Style | Weekday name row style |
day_style | Style | Regular day style |
day_hover_style | Style | Day hover style |
selected_style | Style | Selected day style |
outside_month_style | Style | Adjacent-month day style |
nav_style | Style | Navigation button style |
nav_hover_style | Style | Navigation button hover |
nav_disabled_style | Style | Disabled navigation style |
width | Length | Width |
height | Length | Height |
on_select | Callback<(i32, u32, u32)> | Day selected (year, month, day) |
on_prev_month | Callback<()> | Previous month navigation |
on_next_month | Callback<()> | Next month navigation |