BridgeComfortable

Previews use

Applies to every design system preview on the site. The Bridge app chrome stays the same.

Brand

Density

Select

Stable

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 and disabled options.

Updated Oct 16, 2026

Rendered with the real component
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 toolbar, a table filter or a dense settings row (size sm).

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

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.

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.

44 tokens 26 semantic or component, change with theme and brand 6 density, change with comfortable or compact 12 from the shared scales

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.

Prop Type Default Description
options required SelectOption[] none The choices. Keep them under about ten; use Combobox for long or searchable lists.
placeholder string 'Select an option' Text shown when nothing is selected. Describe the choice, not the action: "No theme".
value string | null none Selected value (controlled). `null` means nothing selected.
defaultValue string | null none Initially selected value (uncontrolled).
onValueChange (value: string | null) => void none Called with the new value when the user picks an option.
label string none Visible label. When set, the Select wraps itself in a Field. Leave unset inside a Field.
hint ReactNode none Help under the label (Field description). Only with `label`.
error ReactNode none Error message. Marks the select invalid and announces the message. Only with `label`.
hideLabel boolean none Visually hide the Field label (it stays the accessible name).
required boolean none No description in the code yet.
name string none Name for form submission (a hidden input carries the value).
size 'sm' | 'md' | 'lg' 'md' Height follows the density tokens. Default `md`.
prefix ReactNode none Content before the value, usually an Icon.
open boolean none Popup open state (controlled).
defaultOpen boolean none Open on first render (uncontrolled).
onOpenChange (open: boolean) => void none No description in the code yet.

Playground

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

<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 (6)

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

Open

AllStates

Changelog

  • New

    Forms: Field (label, description, error wired by Base UI Field) and Input rebuilt on it (prefix, suffix, sizes; label, hint and error props kept). New Textarea (autosize, character count), Select (groups, descriptions), Combobox (filtering, async loading and empty states, multiple with chips), Checkbox (indeterminate, parent), CheckboxGroup, RadioGroup, Switch, Slider (single and range), NumberField (steppers, units) and Form (server errors with a focusable error summary, FormActions footer).

    Unreleased (current version 0.1.0, no release tagged yet) , Oct 17, 2026

All release notes