You're in the Library

Select

Picks one value from a short, known list in a popup. The trigger looks like an Input so forms read as one family; the list supports groups, descriptions, badges and disabled options.
Stable
Edit

Preview appears after the next Storybook update.

Select example
<Select />
Rendered with the real componentFrom the code
Light
Dark

When to use

Use it for

  • One choice from about 4 to 10 known options: a theme, a brand, a token group, a role.
  • The options are long words or labels that would crowd a RadioGroup.
  • Space is tight: in a dense toolbar, a menu or a settings row (size sm). In a page's filter bar, size md, like the search field beside it.
  • Each option carries a short fact worth seeing before the pick, like a status or a count: put a Badge in badge. It shows on the item and in the trigger once selected.

Not for

  • Two or three options that should all stay visible: use RadioGroup, or an attached ButtonGroup for a view switch.
  • Long or unknown lists (people, repositories, 20+ tokens): use Combobox so users can type to filter.
  • Several values at once: use Combobox with multiple, or a CheckboxGroup.
  • Actions (Duplicate, Delete): use Menu. A Select changes a value, it does not run commands.

Do and don't

Every example is rendered with the real component, so it always matches what ships.

Do

A status next to the label with badge

A Badge in the option's badge slot says the status at a glance, in the list and in the trigger. The description stays for a second line of detail, like who made it.

Do

Order options by meaning, not alphabetically by default

Put the most common choice first, or follow the natural order (System, Light, Dark). Group long lists under short headings.

Do

Explain a disabled option

A description on the option says why it cannot be picked, instead of leaving users guessing.

Don't

A Select with two options

Hiding two choices behind a click costs a step for nothing. Show them as radios or a Switch.

Don't

The placeholder as an instruction

"Click to select" says nothing. The placeholder describes the empty state: "No theme", "Any reviewer".

Accessibility

  • Base UI Select: the trigger is a combobox button with aria-expanded; the popup is a listbox with options marked aria-selected and aria-disabled.
  • Keyboard: Enter, Space or Arrow keys open it; arrows move; typing jumps to a matching option; Enter selects; Escape closes and returns focus to the trigger.
  • The Field label names the trigger; hint and error are linked through aria-describedby, and an error sets aria-invalid.
  • The selected option shows a check mark and a medium weight, not color alone.
  • The trigger edge uses color.border.strong (3:1 against surfaces) and the signal focus ring on keyboard focus.
  • The popup is portaled and re-applies the theme, brand and density of its trigger.

Content guidelines

  • Label is a noun in sentence case: "Theme", "Brand", "Reviewer role".
  • Options are short, parallel nouns, sentence case, no trailing punctuation.
  • Group headings are one or two words and never repeat the label.
  • Placeholders describe the empty value ("No theme"), not the action.

From the code Generated from the component, not editable here.

Anatomy and tokens

Read from packages/react/src/components/Select/Select.module.css at build time. Every value is a token: open one to see its alias chain in both themes.

43 tokens26 semantic or component, change with theme and brand6 density, change with comfortable or compact11 from the shared scales

Motion and interaction

Select animates on hover, open and close. Try it in the preview at the top.

PartWhenWhat changesDurationEasing
TriggerHoverBordermotion.duration.instant75 msmotion.easing.standardsettles in place
TriggerOpen and closeBorder, shadow and movementmotion.duration.fast150 msmotion.easing.standardsettles in place
PopupOpenFade and movementmotion.duration.fast150 msmotion.easing.enterstarts fast, lands softly
PopupCloseFade and movementmotion.duration.fast150 msmotion.easing.exitstarts softly, leaves fast

With reduced motion turned on, every change happens at once.

From the code Generated from the component, not editable here.

Props

Parsed from the TypeScript types in packages/react/src/components/Select/Select.tsx, so this table cannot drift from the code. It also accepts every native <button> attribute except value, defaultValue, onChange, prefix, children.

PropTypeDefaultDescription
optionsrequiredSelectOption[]noneThe choices. Keep them under about ten; use Combobox for long or searchable lists.
placeholderstring'Select an option'Text shown when nothing is selected. Describe the choice, not the action: "No theme".
valuestring | nullnoneSelected value (controlled). `null` means nothing selected.
defaultValuestring | nullnoneInitially selected value (uncontrolled).
onValueChange(value: string | null) => voidnoneCalled with the new value when the user picks an option.
labelstringnoneVisible label. When set, the Select wraps itself in a Field. Leave unset inside a Field.
hintReactNodenoneHelp under the label (Field description). Only with `label`.
errorReactNodenoneError message. Marks the select invalid and announces the message. Only with `label`.
hideLabelbooleannoneVisually hide the Field label (it stays the accessible name).
requiredbooleannoneNo description in the code yet.
namestringnoneName for form submission (a hidden input carries the value).
size'sm' | 'md' | 'lg''md'Height follows the density tokens. Default `md`.
prefixReactNodenoneContent before the value, usually an Icon.
openbooleannonePopup open state (controlled).
defaultOpenbooleannoneOpen on first render (uncontrolled).
onOpenChange(open: boolean) => voidnoneNo description in the code yet.
portalContainerHTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | nullnoneWhere the popup is rendered. Default: the end of the body, above every layer including a Dialog or Drawer, so the list is never covered. Pass an element (or a ref) to keep it inside a container, for example a shadow root.

Playground

Change the props and see the real Select update. Controls are generated from the TypeScript props; nothing here changes the system.

Code for these props
<Select
  placeholder="No theme"
  label="Theme"
  defaultValue="dark"
/>

size

Workbench

For contributors: every state with the accessibility panel, in the component workbench (Storybook). The stories double as visual test fixtures; the guidance on this page is the user documentation (open Select in Storybook).

Embed Storybook stories here (7)

Loads from https://bridge-storybook.floriangouloubi.com (set STORYBOOK_URL at build time). If Storybook is not running, the frames stay empty.

Default

WithValue

WithError

Grouped

WithBadges

Open

AllStates

From the code Generated from the component, not editable here.

Changelog

  • New

    The measure now writes the Figma sets drawn under a component's folder as their own entries, so Claude can fix them: popups drawn open (Dialog/Popup, AlertDialog/Popup, Drawer/Popup, Menu/Popup, Popover/Popup, Tooltip/Popup, and Select/Popup or Combobox/Popup, measured open when the stories show them closed) and sets that fix a prop (Pagination/Full, Pagination/Compact, Progress/Linear)

    v1.0.0, Nov 11, 2026

  • New

    Push works like publishing a library in Figma: a Changes list grouped Variables and Components with a checkbox per item (all checked by default, select all per group), a Description that opens the pull request and every request, and one "Push for review"

    v1.0.0, Nov 11, 2026

  • Fix

    Component specs treat a button or a select (including the Base UI part that renders one, read from Base UI's docs) as border-box: NumberField steppers are their height token wide again

    v1.0.0, Nov 11, 2026

  • Fix

    Component specs count height and width as the content box (a bordered table cell is its height plus its border), the Figma build draws an empty sized slot at its padding instead of 100px, and stories reach every Figma variant: a disabled control on IconButton, Input, Select, Combobox and Textarea, and Figma variant stories for AccordionItem, MenuItem, MenuCheckboxItem, MenuSubmenu and TableEmpty

    v1.0.0, Nov 11, 2026

  • Fix

    Select and Combobox: the highlighted option's corners now follow the popup's corners, like Menu items

    v1.0.0, Nov 11, 2026

  • Fix

    Select: the label and badge row in the trigger now applies to every Select, not only disabled ones

    v1.0.0, Nov 11, 2026

  • Fix

    Library review, List: each family's select-all checkbox is always shown

    v1.0.0, Nov 11, 2026

All release notes