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:
dotnet runThe 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:
dotnet runThe PickerSelectionChangedEventArgs provides:
SelectedIndex- The index of the newly selected itemSelectedText- The text of the newly selected itemWidget- The source PickerWidgetNode- The underlying PickerNodeContext- 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:
dotnet runThe 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)
| Input | Action |
|---|---|
| Enter | Open the picker popup |
| Space | Open the picker popup |
| Click | Open the picker popup |
| Tab | Move focus to next widget |
| Shift+Tab | Move focus to previous widget |
Popup State (Picker Open)
| Input | Action |
|---|---|
| Up Arrow | Move to previous item |
| Down Arrow | Move to next item |
| Enter | Select current item and close |
| Click | Select clicked item and close |
| Escape | Close 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:
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();2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Picker-Specific Theme Elements
| Element | Type | Default | Description |
|---|---|---|---|
ForegroundColor | Hex1bColor | Default | Text color for the button |
BackgroundColor | Hex1bColor | Default | Background for the button |
FocusedForegroundColor | Hex1bColor | Black | Text when focused |
FocusedBackgroundColor | Hex1bColor | White | Background when focused |
LeftBracket | string | "[ " | Left bracket text |
RightBracket | string | " ▼]" | Right bracket with indicator |
MinimumWidth | int | 10 | Minimum 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
OnSelectionChangedcallback 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
Popup Behavior
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
Related Widgets
- ButtonWidget - For single actions without selection
- ListWidget - For always-visible selection lists
- ToggleSwitchWidget - For binary or small-set choices
- TextBoxWidget - For free-form text input