Skip to content

ListWidget

A selectable list of text items with keyboard and mouse navigation.

Lists are interactive, focusable widgets that allow users to navigate through items and select or activate them. They're ideal for menus, file browsers, todo lists, and any UI requiring item selection.

Basic Usage

Create a list using the fluent API with an array of strings:

csharp

Navigation

Use Up/Down arrows to move between items. The selected item is highlighted when the list has focus. Press Tab to move focus to other widgets.

Selection Changed Events

The OnSelectionChanged event fires whenever the user navigates to a different item:

csharp

The ListSelectionChangedEventArgs provides:

  • SelectedIndex - The index of the newly selected item
  • SelectedText - The text of the newly selected item
  • Widget - The source ListWidget
  • Node - The underlying ListNode
  • Context - Access to the application context

Selection vs Activation

OnSelectionChanged fires when navigating with arrow keys. Use OnItemActivated (shown below) to respond to Enter/Space/Click actions.

Item Activated Events

The OnItemActivated event fires when the user activates an item with Enter, Space, or mouse click:

csharp

The ListItemActivatedEventArgs provides:

  • ActivatedIndex - The index of the activated item
  • ActivatedText - The text of the activated item
  • Widget - The source ListWidget
  • Node - The underlying ListNode
  • Context - Access to the application context

Common Pattern

Use OnItemActivated for actions like toggling checkboxes, opening details, or navigating to a new screen. Use OnSelectionChanged for updating dependent UI like preview panes.

Event Handlers

Both OnSelectionChanged and OnItemActivated accept synchronous and asynchronous handlers:

Synchronous Handler

csharp
v.List(items).OnItemActivated(e => {
    Console.WriteLine($"Activated: {e.ActivatedText}");
})

Asynchronous Handler

csharp
v.List(items).OnItemActivated(async e => {
    await SaveSelectionAsync(e.ActivatedIndex);
})

Render Loop Blocking

Async handlers block the render loop while awaiting. For long operations, use the background work pattern shown in the ButtonWidget documentation.

Keyboard Navigation

Lists support comprehensive keyboard navigation:

KeyAction
Up ArrowMove to previous item (wraps to last)
Down ArrowMove to next item (wraps to first)
EnterActivate current item
SpaceActivate current item
TabMove focus to next widget
Shift+TabMove focus to previous widget

Wrap-Around Navigation

When reaching the first item, pressing Up wraps to the last item. Similarly, pressing Down at the last item wraps to the first.

Mouse Support

Lists support mouse interaction in terminals that support mouse events:

  • Left Click - Selects the clicked item (fires OnSelectionChanged if selection changed) and then activates it (fires OnItemActivated)
  • Mouse Wheel Up - Moves selection to the previous item
  • Mouse Wheel Down - Moves selection to the next item

Long Lists with Scrolling

When a list has more items than can fit in its container, it automatically becomes scrollable. The viewport scrolls to keep the selected item visible as you navigate:

csharp

Use the .FixedHeight() extension to constrain the list to a specific number of rows. The list will:

  • Show only the visible items within the viewport
  • Automatically scroll when navigating beyond visible bounds
  • Keep the selected item centered when possible
  • Support both keyboard and mouse wheel scrolling

Performance

Long lists are efficient because only visible items are rendered. You can safely use lists with hundreds of items without performance concerns.

Focus Behavior

Lists visually indicate their focus and selection state:

StateAppearance
Unfocused, item selected> Item (indicator only)
Focused, item selected> Item (highlighted with theme colors)
Unfocused, item not selected Item (no indicator)
csharp

When a list loses focus, the selected item still shows the selection indicator but without the highlighting. This helps users track which item was last selected.

Theming

Customize list appearance using theme elements:

csharp
var theme = Hex1bTheme.Create()
    .Set(ListTheme.SelectedForegroundColor, Hex1bColor.Black)
    .Set(ListTheme.SelectedBackgroundColor, Hex1bColor.Cyan)
    .Set(ListTheme.SelectedIndicator, "▶ ")
    .Set(ListTheme.UnselectedIndicator, "  ");

await using var terminal = Hex1bTerminal.CreateBuilder()
    .WithHex1bApp((app, options) =>
    {
        options.Theme = theme;
        return ctx => /* ... */;
    })
    .Build();

await terminal.RunAsync();

Available Theme Elements

ElementTypeDefaultDescription
ForegroundColorHex1bColorDefaultText color for unselected items
BackgroundColorHex1bColorDefaultBackground for unselected items
SelectedForegroundColorHex1bColorWhiteText color when focused and selected
SelectedBackgroundColorHex1bColorBlueBackground when focused and selected
SelectedIndicatorstring"> "Indicator for selected items
UnselectedIndicatorstring" "Indicator for unselected items

Custom Indicators

Change the selection indicators to match your app's style. Common alternatives include "→ ", "● ", "▸ ", or emoji like "👉 ".

State Management

Lists preserve their selection state across reconciliation. The selected index is managed internally by the ListNode and persists even when the widget tree is rebuilt.

When the items list changes, the selection is automatically clamped to valid bounds:

  • If the selected index is beyond the new list length, it moves to the last item
  • If the list becomes empty, the selection resets to index 0

Released under the MIT License.