Skip to content

List

List is a focusable, theme-aware list component. The focused row lives in app state as an index; optional selected rows also live in app state. Moving with Up and Down emits the next focused index. ListWidget is the paint-only layer.

Focus the demo, use Up and Down to move focus, press Enter to select the focused item, and press Alt+T to choose a bundled theme.

Interactive Component

rust
use ratcn::List;
use ratcn::view::View;

const ITEMS: [&str; 3] = ["Inbox", "Archive", "Settings"];

struct AppState {
    focus: FocusState,
    theme: Theme,
    focused_item: usize,
    selected_item: Option<usize>,
}

enum Msg {
    FocusChanged(FocusState),
    FocusedItemChanged(usize),
    ItemSelected(usize),
}

View::new("root")
    .focus(|s: &AppState| &s.focus, Msg::FocusChanged)
    .theme(|s: &AppState| &s.theme)
    .child(
        "list",
        List::new(ITEMS)
            .focused_row(|s: &AppState| s.focused_item)
            .selected(|s: &AppState| s.selected_item)
            .on_focus_change(Msg::FocusedItemChanged)
            .on_select(Msg::ItemSelected),
    )
    .content(|frame, _state, view| view.render_child(frame, "list", area));

List API

  • List::new(items): Creates a list from strings or string-like values.
  • .focused_row(|state| index): Reads the focused row index from app state. Out-of-range indexes clamp to the last item.
  • .selected(|state| Option<usize>): Reads a single selected row from app state. Out-of-range indexes are ignored.
  • .selected_many(|state, index| bool): Reads multi-selection membership from app state.
  • .on_focus_change(Msg::Ctor): Emits the next focused index when Up or Down moves.
  • .on_change(Msg::Ctor): Backwards-compatible alias for .on_focus_change(...).
  • .on_select(Msg::Ctor): Emits the current focused index when Enter is pressed.
  • .render_item(|state, row| Line::from(...)): Customizes row rendering with ListItemState.
  • .focus_symbol(symbol): Sets the symbol shown before the focused row. Pass "" to hide it.
  • .disabled(|state| ...): Renders disabled, ignores events, and leaves Tab traversal while true.

List is focusable only when it has at least one item and is not disabled.

Events

Up moves to the previous item. Down moves to the next item. Enter selects the current item. Modified keys are ignored, so app-level shortcuts can use Ctrl, Alt, or Shift combinations without conflicting with the list.

If .on_focus_change(...) is omitted, Up and Down are consumed but no message is emitted. If .on_select(...) is omitted, Enter is consumed but no message is emitted. Disabled and empty lists ignore events.

Custom Rows

Use .render_item(...) when the default marker/text row is not enough. The closure receives ListItemState with index, item, focused, selected, and disabled fields.

rust
List::new(ITEMS)
    .focused_row(|s: &AppState| s.focused_item)
    .selected_many(|s: &AppState, index| s.selected_items.contains(&index))
    .on_focus_change(Msg::FocusedItemChanged)
    .on_select(Msg::ToggleItem)
    .focus_symbol("")
    .render_item(|_state, row| Line::from(format!("{} {}", row.index + 1, row.item)));

Paint Widget

Use ListWidget when you only need rendering.

rust
use ratatui::text::Line;
use ratcn::ListWidget;

let items = vec![Line::from("Inbox"), Line::from("Archive")];
let selected_rows = [1];

frame.render_widget(
    ListWidget::new(&items)
        .focused_row(Some(focused_item))
        .selected_rows(&selected_rows)
        .focused(contains_keyboard_focus)
        .themed(&theme),
    area,
);
MethodDescription
ListWidget::new(&items)Creates a paint-only list over &[Line<'static>].
.focused_row(Some(index))Marks the focused row.
.focused_row(None)Renders without a focused row.
.selected_rows(&indexes)Highlights selected rows.
.focused(bool)Controls the focused-row symbol.
.is_focused()Returns whether focused styling is enabled.
.disabled(bool)Draws disabled styling.
.is_disabled()Returns whether disabled styling is enabled.
.themed(&theme)Applies theme colors.
.style(ListStyle)Uses an explicit style.
.focus_symbol(symbol)Sets the focused-row symbol.