Multi Select
Headless compact multi-value selection primitives.
Multi Select in motion
When to use
Use MultiSelect when users choose several values from a predefined moderate collection and the options should stay collapsed until requested. Use CheckboxGroup for a short visible choice set, Listbox when the collection should remain visible, Select for one value, and Combobox when editable filtering is required.
Features
The behavior Atom owns before your product adds appearance.
- Coordinates controlled and uncontrolled multi-value selection while keeping the popup open as options are toggled.
- Provides listbox semantics, roving option focus, typeahead, keyboard selection, focus restoration, and completed outside-interaction dismissal.
- Supports Field and Form relationships, native multiple-select participation, required validation, reset behavior, and disabled, readonly, and invalid states.
- Includes positioned popup, portal, viewport, group, label, separator, indicator, scroll-button, and arrow anatomy.
Import
Anatomy
API Reference
Root
| Prop | Type | Default |
|---|---|---|
children | ReactNode | required |
value | string[] | - |
defaultValue | string[] | [] |
onValueChange | (value: string[]) => void | - |
open / defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | - |
disabled / readOnly / invalid / required | boolean | Field value / false |
name / form | string | - |
validationBehavior | "native" | "inline" | Field/Form value |
Values are deduplicated in first-occurrence order. Item activation toggles one value without closing Content. Uncontrolled value and open state return to their defaults on form reset.
Parts
Triggerrenders a button and ownsaria-expanded,aria-haspopup,aria-controls, Field label/description relationships, state data, native props, ref,asChild, andrender.Valuerenders the placeholder for zero values, one label for one value, orFirst (+N more)for several.renderValue(values, labels)customizes the summary without changing behavior.Contentand itsListboxalias render the positioned popup, portal by default, exposedata-side,data-align, anddata-positioned, and acceptonInteractOutside(event). Callingevent.preventDefault()keeps the popup open without cancelling the outside destination activation.Viewport, scroll buttons, andArrowown the specialized overflow and positioned-popup anatomy.Itemrequiresvalue, acceptslabelanddisabled, exposes option ARIA, checked/highlighted/disabled data, and stays open after toggling.ItemText,ItemIndicator,Group,Label, andSeparatorpreserve the complete collection anatomy.Portalacceptscontaineranddisabled.
Accessibility and keyboard
Trigger is a button that opens a focusable popup listbox; it is deliberately
not role="combobox" because the APG combobox value model is single-select.
Content has role="listbox" and aria-multiselectable="true"; Items have
role="option" and aria-selected.
- Arrow keys move the active option without changing selection.
- Home/End move to the first/last enabled option.
- Space or Enter toggles the active option and keeps Content open.
- Printable keys use option labels for typeahead.
- Escape closes and restores Trigger focus.
- Tab and completed mouse, touch, pen, or virtual outside activation close the popup; dragged and cancelled pointer sessions do not.
Forms and Field
When named or required, Root renders an accessibility-hidden native multiple select containing every declared Item. It carries the selected values, name, form, disabled, and required state; redirects invalid focus to Trigger; and uses Atom's Field/Form validation and reset infrastructure. Item labels are collected statically so closed values and native options work before the popup mounts.
Data Attributes
- Trigger and Content expose
data-state="open|closed"; Content also exposes resolveddata-side,data-align, anddata-positioned. - Item exposes
data-state="checked|unchecked",data-value, and optionaldata-highlightedanddata-disabled. - Stateful parts expose
data-disabled,data-readonly, anddata-invalidwhere those states apply. Every rendered part exposes an overridabledata-slot.
Scope
MultiSelect intentionally excludes editable filtering, arbitrary tags, creation, select-all, range selection, virtualization, async loading, and mandatory chips. Those require separate interaction contracts.
Changelog
Unreleased
0.24.0
- Added public Agent Knowledge for component selection, required composition, recurring mistakes, and validation.
0.20.0
- Added preventable
Content/Listbox.onInteractOutsideand moved outside dismissal to the shared layer-aware completed-activation contract.
0.10.1
- Move required and read-only ARIA states from the native button trigger to the multiple-selection listbox that supports them.
0.10.0
- Add the complete compact multi-value selection primitive with button-owned popup listbox semantics, array state, summary rendering, positioning, dismissal, Field/Form participation, validation, reset, and full anatomy.