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:

  • label on Root names the search field. It renders a visually hidden <label> that the Input references.
  • aria-label on List names 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

PropTypeDefault
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.booleantrue
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

PropTypeDefault
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 booleanfalse

Input, List, Group, GroupHeading, Empty, Separator and Loading take class plus their native attributes. Viewport, GroupItems and LinkItem are re-exported from Bits unchanged.