Skip to content

Picker

A dropdown picker widget that displays a selected value and opens a popup list when activated.

Pickers are ideal for selecting from a list of predefined options where displaying all options at once would take too much space. They're commonly used in forms for selecting categories, priorities, modes, or any enumerated value.

Basic Usage

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

csharp

The picker displays as a button showing the current selection with a dropdown indicator (). When focused and activated (Enter, Space, or click), a bordered popup appears with all available options.

Navigation

  • Enter or Space - Open the picker popup
  • Up/Down arrows - Navigate items in the popup
  • Enter - Select the highlighted item and close
  • Escape - Close the popup without changing selection

Selection Changed Events

The OnSelectionChanged event fires when the user selects a different item from the popup:

csharp

The PickerSelectionChangedEventArgs provides:

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

Selection Only Changes on Confirmation

Unlike List widgets where OnSelectionChanged fires during navigation, Picker's OnSelectionChanged only fires when the user confirms a selection by pressing Enter or clicking an item. Pressing Escape cancels without firing the event.

Initial Selection

By default, pickers select the first item (index 0). Use the initialSelectedIndex parameter to start with a different selection:

csharp

The initial selection is clamped to valid bounds—if you specify an index beyond the item count, the last item is selected.

Keyboard and Mouse Navigation

Pickers support comprehensive interaction:

Button State (Picker Closed)

InputAction
EnterOpen the picker popup
SpaceOpen the picker popup
ClickOpen the picker popup
TabMove focus to next widget
Shift+TabMove focus to previous widget
InputAction
Up ArrowMove to previous item
Down ArrowMove to next item
EnterSelect current item and close
ClickSelect clicked item and close
EscapeClose without changing selection

Mouse Wheel

In terminals with mouse support, the mouse wheel scrolls through items in the popup when open.

Theming

Customize picker appearance using theme elements. Since Picker is a composite widget made of Button and List, you can theme both components:

csharp
var theme = Hex1bTheme.Create()
    // Button appearance (the picker display)
    .Set(ButtonTheme.ForegroundColor, Hex1bColor.Yellow)
    .Set(ButtonTheme.FocusedBackgroundColor, Hex1bColor.Yellow)
    .Set(ButtonTheme.FocusedForegroundColor, Hex1bColor.Black)
    // List appearance (the popup)
    .Set(ListTheme.SelectedBackgroundColor, Hex1bColor.Cyan)
    .Set(ListTheme.SelectedForegroundColor, Hex1bColor.Black)
    // Border appearance (around the popup)
    .Set(BorderTheme.BorderColor, Hex1bColor.Magenta);

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

await terminal.RunAsync();

Picker-Specific Theme Elements

ElementTypeDefaultDescription
ForegroundColorHex1bColorDefaultText color for the button
BackgroundColorHex1bColorDefaultBackground for the button
FocusedForegroundColorHex1bColorBlackText when focused
FocusedBackgroundColorHex1bColorWhiteBackground when focused
LeftBracketstring"[ "Left bracket text
RightBracketstring" ▼]"Right bracket with indicator
MinimumWidthint10Minimum button width

Theme Propagation

When a picker is inside a ThemePanel, the theme automatically propagates to the popup. This ensures consistent styling even though the popup renders as a separate layer.

State Management

Picker selection state is owned by the underlying PickerNode and preserved across reconciliation. This means:

  • The selection persists when the widget tree rebuilds
  • You don't need to manage selection state yourself unless you want to track it externally
  • The OnSelectionChanged callback lets you synchronize external state when needed

When the items list changes:

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

The picker popup is rendered as an anchored popup positioned below the picker button:

  • The popup appears immediately when the picker is activated
  • It's automatically dismissed when an item is selected or Escape is pressed
  • The popup list matches the button's width for visual consistency
  • Long lists scroll automatically within the popup

Modal Behavior

While the popup is open, focus is trapped within it. The user must select an item or press Escape to return to the main UI.

Composite Widget Pattern

Picker is implemented as a composite widget, meaning it's built from other Hex1b widgets (Button and List) rather than rendering directly. This provides:

  • Consistent behavior: Uses the same Button and List that you'd use directly
  • Theme integration: Button and List theme elements apply naturally
  • Focus management: Focus flows correctly between button and popup list

Released under the MIT License.