List Box

An always-visible list of options. No trigger, no popover: the choices stay on screen, which is what a settings panel, a transfer list or a filter pane wants. It carries the whole ARIA listbox pattern — one tab stop, a roving active option, range selection and typeahead.

Single Selection

The default. One option at a time, bound with @bind-Value. Moving with the arrow keys selects as it goes, which is how a native list behaves. Click into the list and try , Home, End, or just type the first letter of an option.

Multiple Selection, Search and Select All

SelectionMode="ListBoxSelectionMode.Multiple" binds through @bind-Values instead. The arrow keys now move without selecting; Space toggles, Shift with an arrow or a click extends a range, and Ctrl+A takes everything. Select-all covers what the search has left visible, not the hidden rest — a control that quietly selected rows you could not see would be worse than no shortcut at all.

Unavailable Rows and a Custom Row

OptionDisabled takes the whole option rather than a value, so the rule can read either. A disabled row is skipped by the arrow keys, by select-all and by Ctrl+A rather than stopping them dead. ItemTemplate replaces an option's content; the selection indicator is drawn either way, because a focusable checkbox inside every option would be a second tab stop and a second thing to announce when aria-selected already carries the state.

Reading What the Search Left Visible

SearchText is bindable but not required — typing in the search box works whether or not a parent binds it. Bind it when the parent has to know which options are on screen rather than guess. This is exactly what Pick List uses to move only what a search has left visible.

Empty and Disabled States

EmptyMessage defaults to the localized “No matches” while a search is typed and “No options” otherwise. Disabled draws the root at reduced opacity and removes the list from the tab order entirely, so it cannot be reached by keyboard.

Inside an EditForm

Both bindings carry an expression — ValueExpression and ValuesExpression — which Blazor supplies automatically from @bind-Value or @bind-Values. The cascaded EditContext is picked up on its own, so validation works with nothing else wired up.