Usage
Tracks the active option of a multi-select combobox and handles its keys, while DOM focus stays on the control. It powers MultiSelector; unlike useCombobox, toggling an option keeps the list open, and rows can carry an action cell. It renders nothing and sets no attributes: the caller renders the control and the list, and wires the ARIA attributes from what it returns.
tsimport {useMultiCombobox} from '@astryxdesign/core/MultiSelector'
Best practices
| Guidance | Practices |
|---|---|
| Do | Render each option with |
| Do | Use |
| Do | Announce the number of results through useAnnounce when the options change for a new query. |
| Don't | Close the list after each toggle; a multi-select stays open so several options can be picked in a row. |
Parameters
| Param | Type | Description |
|---|---|---|
optionsrequired | UseMultiComboboxOptions | Configuration object. |
options.selectableItemsrequired | [] | The options in the same order as they render. Options with |
options.isOpenrequired | boolean | Whether the list is shown. The caller owns this state. |
options.onOpenrequired | () => unknown | Called to show the list. Return |
options.onCloserequired | () => void | Called to hide the list. The highlight resets first. |
options.onTogglerequired | (itemValue: string) => void | Called with the value of the option to add or remove. Toggling keeps the list open. |
options.listboxIdrequired | string | The listbox (or grid) element's id. Option and action-cell ids are derived from it. |
options.hasSearch | boolean (default: false) | Whether the list has its own search field. Space then types instead of toggling, opening does not pre-highlight, Delete and Backspace edit the query, and type-to-select is off. |
options.onClear | () => void | Clears every selected value. When provided, Delete or Backspace on the closed control clears them, so clearing is not pointer-only. Ignored while the list is open or with |
options.hasValue | boolean (default: false) | Whether anything is selected. The Delete and Backspace clear is skipped when false. |
options.isGrid | boolean (default: false) | Whether each row pairs an option cell with an action cell. The inline-end arrow then moves the highlight to the row's action and the inline-start arrow back, following visual direction in right-to-left layouts, and Enter on the action runs |
options.rowHasAction | (index: number) => boolean | In a grid, whether the row at |
options.onActivateAction | (index: number) => void | In a grid, runs the control in the highlighted row's action cell. The selection does not change. |
options.isDisabled | boolean (default: false) | Whether the control ignores clicks and keys. |
Returns
| Field | Type | Description |
|---|---|---|
| highlightedIndex | number | Index of the active row, or -1 when none is active. |
| setHighlightedIndex | (index: number) => void | Sets the active row, for example after filtering. The highlight lands on the row's option cell. |
| highlightedCell | 'option' | 'action' | Which cell of the active row is highlighted; |
| activeDescendantId | string | undefined | The id to pass as the control's |
| getItemId | (index: number) => string | The id to render on the option at |
| getActionCellId | (index: number) => string | In a grid, the id to render on the action cell of row |
| onTriggerClick | () => void | Toggles the list from a press on the control. |
| onKeyDown | (e: React.KeyboardEvent) => void | Key handler for the control that keeps focus. ArrowDown and ArrowUp open the list or move the active row; Enter (and Space without search) toggles the active option and keeps the list open; Escape and Tab close it; Home, End, PageUp and PageDown jump to the first or last option; without search, typed characters move to the first option whose label starts with them. |
| onItemMouseEnter | (item: , index: number, cell?: 'option' | 'action') => void | Makes the hovered option, or its action cell, active without scrolling the list or moving focus. |
Use with shadcn
Already using the shadcn registry workflow? Install the real Astryx package and a local public re-export. Component implementation source stays in Astryx. How compatibility works.
This install URL expires with the draft preview.bashnpx shadcn@4.19.0 add https://astryx-flegw5w6l-fbopensource.vercel.app/shadcn/hooks/use-multi-combobox.json