Multi-select combobox with chip-based selected values, optional search, and max-selection cap.
Combobox + listbox with aria-multiselectable
Chip rendering for selected values with keyboard removal (Backspace)
Optional searchable filter and clearable affordance
Max-selection cap with live count footer
Surface-aware (flat/linear) field shell with hint/error states
Status
stable
Category
forms
Since
v1.8.0
API
import { PixelMultiSelect } from '@pxlkit/ui-kit';
Prop
Type
Default
Description
value
string[]
—
The selected values, in the order picked; leave unset for an uncontrolled multi-select.
defaultValue
string[]
—
Initial values while uncontrolled.
onChange
(next: string[]) => void
—
Called with the selected values after every toggle, removal or clear.
options* (required)
PixelMultiSelectOption[]
—
The options of the listbox.
searchable
boolean
false
Shows a search field that filters the options.
max
number
—
Most values that can be selected.
placeholder
string
'Select…'
Text shown while nothing is selected.
clearable
boolean
false
Shows a button that clears the selection while there is one.
surface
'pixel' | 'linear'
—
Surface override; defaults to the nearest provider.
size
'sm' | 'md' | 'lg'
'md'
Trigger height.
label
string
—
Label rendered above the trigger.
hint
string
—
Helper text below the field; hidden while error is set.
error
string
—
Error message below the field; marks the trigger invalid.
name
string
—
Hidden-input name. Multiple values are serialized as repeated <input type="hidden" name={name}> entries; read with FormData.getAll(name).
id
string
—
id of the trigger; generated when left out.
ref points to <button>.
Accessibility
WCAG target: 2.1 AA
combobox
listbox
The field holds, side by side, the chips — each a label and a native button named after it ("Remove Apple") — the combobox and, when clearable, a native "Clear selection" button: a button cannot contain a button, so none sits inside another, and each is a tab stop in reading order. The combobox (role=combobox, named by the label) has aria-controls/expanded/activedescendant, and so does the search field while focus is in it; it reads the selected labels as its value. A remove or clear button that holds focus hands it on as it goes; under the pointer they leave focus where it is. A press elsewhere on the field opens or closes the listbox and focuses the combobox; the popover anchors to the field. The field shows the combobox's keyboard focus. Listbox advertises aria-multiselectable and marks the chosen options aria-selected.
Keyboard
Key
Action
When
Tab
Move through the field: each chip's remove button, the combobox, then the clear button
—
ArrowDown
Open popover or move highlight down
—
ArrowUp
Open popover or move highlight up
—
Home
Highlight first option
—
End
Highlight last option
—
Enter
Toggle highlighted option
—
Space
Toggle highlighted option from the combobox; types a space in the search field
—
Backspace
Remove last selected chip when query is empty
—
Escape
Close the popover; from the search field, focus returns to the combobox
popover open
Enter / Space
Remove the chip and focus the next chip's remove button, else the combobox