Form-bound value picker built on React Aria, from a plain one-of-many list to searchable, grouped, rich, and multi-select pickers.
Description
Select is a compound value picker built on React Aria's Select. It composes a Select.Trigger (with Select.Value), a Select.Popover surface, and a list of Select.Item rows, with optional Select.Group, Select.Label, Select.Search, Select.Shell, and Select.Separator slots. The list, items, and section headings are the same surface as Dropdown and Combobox, so a row looks identical across all three. size is set on the root and cascades through context to the trigger, items, labels, and icons.
Reach for it for a value the form submits: country, currency, role, status, plan, payment method. It binds to a Field for its label and its size/invalid/disabled/loading cascade, and drops into an InputGroup as a compact leading picker. Pass selectionMode="multiple" and it becomes a multi-select you render as chips. Add a header={<Select.Search />} to the popover and the panel filters as you type, without turning the trigger into a text field.
The free tier covers the trigger, plain Select.Item rows, the default and compact variants, the three sizes, the invalid/disabled/loading states, controlled usage, the input-group embed, and the chip multi-select. Smart items (a leading media slot, a secondary description, a trailing slot), grouped Select.Group + Select.Label, the pinned Select.Search bar, the footer, and the rich multi-select picker are Pro; the live demos still run, but the source needs a Pro seat. Do not use a select for a long list users must filter to navigate (use Combobox), for a menu of commands rather than a value (use Dropdown), for a handful of always-visible options (use Radio Group), or for a boolean (use Switch).
Installation
Anatomy
Usage
Examples
The free tier covers the trigger, plain items, variants, sizes, states, controlled usage, the input-group embed, and the chip multi-select. Richer previews (smart items, search, grouped sections, the rich user picker) are marked with a Pro badge; the live demo still runs, but the source needs a Pro seat.
Variants
variant="default" is a full-width trigger with placeholder text, the form-field shape. variant="compact" shrinks the trigger to fit its content for toolbar pickers and icon-only controls; pair it with aria-label on Select.Trigger.
Sizes
Three sizes (xs, sm, md) set on the root cascade to the trigger, item height, label, and icon size. sm is the default; pick md for hero forms and xs for dense settings tables.
States
Default, isDisabled, isInvalid, and loading. isInvalid tints the border and outline with error tokens; loading swaps the caret for a spinner and locks the field with info tokens. All of them cascade from a surrounding Field.
With icon and badge
Render a leading element inside Select.Trigger to mirror the selected item's icon, and drop a trailing element (such as a Badge) between Select.Value and the auto-rendered caret to surface a secondary label like a ticker.
Controlled
Pass value and onChange to manage the selection yourself. Use uncontrolled defaultValue for simple forms; reach for controlled when other UI needs to react to the selection.
Inside an input group
Drop a Select variant="compact" next to an Input inside InputGroup and the trigger detects the surrounding InputShell, skips its own chrome, and lets the group own the single shared border and focus ring.
Multi-select
Pass selectionMode="multiple" with a value array. Intercept onChange to keep an array in state and render the selection as Chips inside the trigger; the popover stays open between clicks.
Rich items
A smart item takes a leading icon, a secondary description line, and an indicator for the selected check. The item surface is shared with Dropdown, so the row looks identical.
Searchable token picker
Pass header={<Select.Search />} to Select.Popover and the panel filters as you type against each item's textValue, while the trigger stays a value display. Grouped Your assets / Popular sections hold rich items with a brand icon, a price description, and a trailing holdings amount, with an empty state and an error footer.
Searchable card picker
Two-line items (a brand mark leading, a masked number description) behind a Select.Search, with a no-match empty state and a footer action to add a new card.
Multi-select user picker
A multi-select assignee list: a leading Checkbox beside member avatars (composed from the item sub-parts), the selection shown as chips with a +N more overflow in the trigger, and an apply / clear footer.
Insert block
A command-style select with a Pro upsell: grouped items with a selection check, a separated AI Block row, and a footer pairing an "Unlock with Pro" badge with an upgrade button.
Accessibility
Select inherits React Aria's select and listbox interaction model. The trigger is a single tab stop; arrow keys, type-ahead, and Home / End operate inside the open listbox.
ARIA notes:
- React Aria wires
role="button"witharia-haspopup="listbox"on the trigger,role="listbox"on the popover, androle="option"on items, plusaria-expanded,aria-activedescendant, andaria-selected. - The root forwards
isInvalidtoaria-invalidon the trigger (and reads it fromFieldcontext when unset);loadingsetsaria-busy="true"and disables the control. - For
variant="compact"(an icon-only trigger), always passaria-labelonSelect.Triggerso the control announces its purpose. - The searchable variant wraps the panel in a React Aria
Autocomplete: theSelect.Searchinput keeps DOM focus while arrow keys drive virtual focus in the listbox, and items filter against theirtextValue. ProviderenderEmptyStateso a no-match hint can show. - For deeper focus, portal, and filtering behavior, see the React Aria Select docs.
Styling
Tailwind override: pass className to merge Tailwind classes on the trigger, the popover, or any sub-part (merged via cn()):
Data slots and attributes: the component sets these for CSS targeting:
data-slot="select"on the root,select-shellon the chrome wrapper,select-triggeron the trigger,select-valueon the value,select-contenton the popover,select-listboxon the list,select-searchon the pinned search bar,select-groupon a group,select-labelon a heading,select-itemon a row,select-item-trailingon the trailing slot, andselect-separatoron a divider. The item internals reuse the dropdown slots:dropdown-item-container/dropdown-item-content/dropdown-item-label/dropdown-item-description/dropdown-item-indicator, plusdropdown-footer.data-size="xs" | "sm" | "md",data-variant="default" | "compact", anddata-invalid/data-loading/data-placeholdermirror the resolved state on the shell and trigger.- The trigger carries
data-state="open" | "closed"; the searchable trigger reuses theInputshell so itsfocus-within,invalid,disabled, andloadingborders are identical to a plainInput. - React Aria manages
data-focused,data-selected, anddata-disabledon each item; wrappers style throughgroup-data-[focused]/itemandgroup-data-[selected]/item.
Target a state in CSS:
Related Components
- Combobox: the same list surface with a text-input trigger, for long lists you filter as you type or values that might not be in the list.
- Dropdown Menu: the same list surface opened from a button, for commands and actions rather than a value.
- Radio Group: flat one-of-many selection kept inline; use it for 2-4 options where surfacing every choice saves a click.
- Native Select: a native
<select>wrapper; reach for it when the form must work without JavaScript or you want the OS picker on mobile. - Input Group: the chrome wrapper used in the embedded-select pattern.
API Reference
Select.* reuses the Dropdown/Combobox item surface, so item props match Dropdown.Item. The select-specific parts are the root, Select.Trigger, Select.Value, Select.Shell, Select.Popover, and Select.Search.
Select
The root. Wraps React Aria's Select, so its selection and collection props pass through. Provides the size/variant/state context.
Props
Variants
Select.Trigger
The button that opens the listbox and shows the value. Wraps a leading element and a Select.Value, and auto-renders the trailing caret (or a spinner while loading). Standalone it wraps itself in Select.Shell; inside an InputGroup or a Select.Shell it renders bare so the container owns the chrome.
Props
Select.Value
Renders the selected item's label, or the placeholder when nothing is selected.
Props
Select.Shell
Manual chrome wrapper for hand-rolled trigger layouts (for example composing a select beside another input). Reads size, variant, and state from context. Extends React.ComponentProps<"div">.
Select.Popover
The floating surface (alias Select.Content). Renders the ListBox. Extends React Aria's PopoverProps; defaults to placement="bottom start" and offset={8}. Providing header wraps the panel in an Autocomplete so a Select.Search inside it filters the list.
Props
Select.Search
A pinned search field for the searchable variant. Pass it as header on Select.Popover. Reuses the Input shell.
Props
Select.Item
A list row. A plain label with an optional leading media, value (alias for id), and textValue are free; description, trailing, and indicator opt into the smart layout (Pro). React Aria ListBoxItem props (isDisabled, and a render-function child receiving { isSelected }) pass through. The type-ahead and search filter match against textValue.