Command
Command palette / fuzzy search menu.
Usage
The command-palette pattern. Bits owns the filtering, the scoring and arrow-key navigation, and it keeps focus in the Input while the highlight moves — so the user types and navigates without ever leaving the field. To open it in a modal, wrap the whole thing in a Dialog.
Try typing trash — it matches Delete, which does not contain the word.
Viewport is required
Command.Viewport goes inside List and wraps
the content. It is not optional.
Bits takes the Input's aria-controls from the Viewport's id, and uses
the Viewport as the insertion element when sorting filtered items. Omit it and the combobox is
invalid ARIA — axe reports aria-required-attr, because a role="combobox" with aria-expanded must say what
it controls.
This is not hypothetical: our own a11y suite caught a Command built without one, which is why it is called out here rather than left as a detail in the API table.
Naming the field and the list
There are two names to set, and the prop names do not make that obvious:
labelonRootnames the search field. It renders a visually hidden<label>that the Input references.aria-labelonListnames the list. Bits defaults it to"Suggestions...", which says nothing about what the suggestions are — override it.
We deliberately leave Bits' default in place rather than silently substituting our own, so the behaviour matches their documentation. Setting both is on you.
Keywords and filtering
value is what the query matches against. Add keywords for the words a user would actually type but that are not in
your label — trash on a Delete item, preferences on Settings. This is the difference between a palette people
use and one they abandon because it never finds anything.
A group whose items are all filtered out is hidden along with its heading, so you never get a
heading over nothing. Set shouldFilter=false when you filter server-side
and render only what you want shown.
Async results
Use Loading while a request is in flight, not Empty. "No results" and "still loading" are different answers, and
showing the first one during a fetch tells the user to stop typing when they should wait.
Always render one or the other — a palette that goes silently blank reads as broken.
Props
Command.Root
| Prop | Type | Default |
|---|---|---|
value The highlighted item's value. Bindable. | string | '' |
class Extra classes merged onto the root. | string | — |
label Screen-reader-only name for the SEARCH FIELD (renders a hidden label the Input references). | string | — |
shouldFilter Set false when filtering server-side; then render only the items you want shown. | boolean | true |
filter Custom scoring, 0 to 1. Defaults to computeCommandScore. | (value, search, keywords?) => number | — |
onStateChange Called when the search, value or filtered set changes. | (state) => void | — |
Command.Item
| Prop | Type | Default |
|---|---|---|
class Extra classes merged onto the item. | string | — |
value required What the query is matched against, and what Root reports as the selected value. | string | — |
keywords Extra terms that should match this item but are not in its label. | string[] | — |
onSelect Called when the item is chosen. | () => void | — |
disabled | boolean | false |
Input, List, Group, GroupHeading, Empty, Separator and Loading take class plus their native
attributes. Viewport, GroupItems and LinkItem are re-exported from Bits unchanged.