Skip to content

ComponentsForms

Select

Pick a single option from a collapsible list. Supports icons, avatars, descriptions, sections, typeahead, form submission and validation.

React AriaSource
Region

Installation

pnpm dlx shadcn@latest add @desyne/select

The CLI installs dependencies and any other components this one uses.

Usage

tsx
import {
  Select,
  SelectItem,
  SelectItemDescription,
  SelectItemLabel,
  SelectSection,
} from "@/components/ui/select";
tsx
<Select label="Role" placeholder="Select a role">
  <SelectItem id="admin">Admin</SelectItem>
  <SelectItem id="member">Member</SelectItem>
  <SelectItem id="viewer">Viewer</SelectItem>
</Select>

When to use

  • Select — one choice from roughly 5–50 known options, where the options don't need to be visible all the time.
  • Radio Group — fewer than ~5 options that benefit from being visible side by side.
  • Combo Box — long lists users will search, or when free-form input is allowed.
  • Menu — a list of actions, not a value.

Anatomy

tsx
<Select>                         {/* field: label, trigger, description, error */}
  <SelectSection title="…">      {/* optional group with a heading */}
    <SelectItem id="…">          {/* option */}
      <Icon />
      <SelectItemLabel />        {/* shown in the trigger */}
      <SelectItemDescription />  {/* shown only in the list */}
    </SelectItem>
  </SelectSection>
</Select>
PartRendersNotes
Select<div> + <button> + popoverWraps label, trigger, description, error message and the listbox popover.
Trigger<button>Shows the selected item (or placeholder), prefix and a chevron.
SelectItemrole="option"An option. Needs a unique id, and textValue if children aren't plain text.
SelectItemLabel<span slot="label">Primary text of a rich item; the only part rendered in the trigger.
SelectItemDescription<span slot="description">Secondary text; hidden in the trigger.
SelectSectionrole="group"Groups options under an optional title.
Hidden <select><select>Rendered for native form submission and browser autofill when name is set.

Examples

Variants

outline (default), filled for dense or tinted surfaces, and underlined for minimal, inline forms. The same variants apply to every field component.

outline
filled
underlined

Sizes

Dynamic items

Pass items and a render function instead of static children. Each item needs an id (or key) property; React Aria only re-renders items that changed.

Framework

Rich items

Compose icons with SelectItemLabel and SelectItemDescription. The trigger shows only the label, so the closed select stays compact. Set textValue for typeahead.

Role

With avatars

Any element works as leading content. Here an Avatar makes people easier to scan.

Assignee

Sections and prefix

SelectSection groups options under a heading. prefix adds an icon to the trigger.

Timezone

Long lists and typeahead

The list scrolls within the available viewport height. With the trigger focused, type a few letters to jump to the first matching option.

CountryFocus the trigger and start typing to jump.

Controlled

Use selectedKey and onSelectionChange to own the value. Set it to null to clear the selection and show the placeholder again.

Status

Selected: in-progress

Disabled

isDisabled disables the whole field; disabledKeys disables specific options while keeping them visible. Use description to explain why.

Region
PlanEnterprise requires a sales call.

Required and validation

isRequired blocks form submission until an option is chosen and shows the browser's message. disabledKeys keeps unavailable options from being selected.

Plan

Custom validation

validate returns an error string (or null). With validationBehavior="aria" on the form, errors show live as the value changes instead of on submit.

RetentionHow long we keep request logs.7 days is below your compliance minimum of 30.

Form submission

Give the select a name and its value is included in FormData, exactly like a native <select>.

Size
Color

Recipes

Filter toolbar

Small selects with icon prefixes next to a SearchField. Each has an aria-label since there's no visible label.

Settings list

A select aligned to the end of each row, labelled by the row's title via aria-labelledby.

Theme

Choose how the app looks.

Language

Used for dates, numbers and the interface.

Start of week

First day shown in calendars.

Dependent selects

The second select's items depend on the first. Reset the child value when the parent changes.

Geography
Region

Accessibility

  • The trigger is a button with aria-haspopup="listbox"; the selected value and label are announced together.
  • Always provide a label: label, aria-label, or aria-labelledby.
  • When name is set, a visually hidden native <select> is rendered so browser autofill and form submission work.
  • description and errorMessage are linked to the trigger with aria-describedby.
  • Typeahead works both on the closed trigger and inside the open list.

Keyboard

KeyAction
Space / Enter / ↓ / ↑Opens the list
↓ / ↑Moves focus between options
Home / EndFocuses the first / last option
Page Up / Page DownMoves focus by a page
Enter / SpaceSelects the focused option and closes
EscCloses the list without changing the value
Any characterTypeahead to the first matching option

Styling

Data attributes

On the Select root (use group-data-*/field: to style children):

AttributePresent when
data-openThe list is open
data-focused / data-focus-visibleThe trigger has focus / keyboard focus
data-disabledisDisabled is true
data-invalidValidation failed
data-requiredisRequired is true (adds the * to the label)

On each SelectItem:

AttributePresent when
data-focused / data-hoveredThe option has virtual focus / hover
data-selectedThe option is the current value
data-disabledThe option is in disabledKeys

Slots

data-slotElement
selectRoot
label, description, field-errorField text
popover, list-boxOverlay and list
list-box-item, list-box-sectionOptions and groups

The popover is at least as wide as the trigger (min-w-(--trigger-width)). Pass a className on Select to size the whole field.

API Reference

Select

Prop

Type

Also accepts every prop of React Aria's Select.

SelectItem

Prop

Type

SelectSection

Prop

Type

SelectItemLabel / SelectItemDescription

Accept every prop of React Aria's Text. They set slot="label" and slot="description" so the option's accessible name and description are wired up automatically.

  • Combo Box — searchable select with free-form input.
  • List Box — the same list, always visible, with multiple selection.
  • Radio Group — for a handful of visible options.
  • Text Field — shares the same field variants and sizes.