Select

Pick one option from a short, known list — options are choices, not actions (actions are Menu), and typing-to-filter belongs to Combobox (layer 2). Its sm/md/lg trigger shares size.interactive with Button, Input, and SegmentedControl. The listbox keeps Menu's dense option geometry at every trigger size: trigger prominence and list density are independent.

Sizes

Height, type, and chevron size move while field geometry stays fixed at space.3 on the text edge, space.2 on the chevron edge, and space.2 between them; medium is the modifier-free default.

ExampleSizeModifierHeightUsage
Small--smsize.interactive.smToolbars, table filters, dense forms
Mediumds-selectsize.interactive.mdForms and most surfaces
Large--lgsize.interactive.lgHigh-emphasis and touch-oriented flows

Trigger states

Input's vocabulary plus Select's own. The open border marks the engaged trigger; the focus ring stays reserved for keyboard focus — the trigger is a button, so border-emphasis focus belongs to text entry.

ExampleStateDriverRolesUsage
Rest, empty[data-placeholder]border.defaulttext.mutedThe empty value is a hint, never essential content
Rest, chosentext.primaryThe chosen option reads like any entered value
Hover:hoverborder.hoverThe border answers the pointer
Open[aria-expanded]border.activeEngaged without stealing the focus ring; the chevron flips
Focus:focus-visiblefocus.ringKeyboard focus — ring, not border
Invalid[aria-invalid]status.error.borderPair with an error message via aria-describedby
Disabled:disabledaction.disabled.bg.textExcluded from interaction and the tab order

Option states

The popover is a listbox, not a menu — a listbox holds options you pick from, a menu holds actions you run. Same dense look, different ARIA: radius.container around radius.nested rows, size.control.sm height, and space.1-5 / space.3 row padding. It spans the trigger width one space.1 below it. The selected option is marked by a check alone—no fill or weight. It is the icon set's check in a size.icon.sm slot that every option reserves, the same mark and the same reservation a checkable menu row carries; a mark that only exists when selected is not a column.

ExampleStateDriverRolesUsage
Washington, D.C. (iad1)
Resttext.primaryradius.nestedA choice using Menu's dense row geometry, never an action
Singapore (sin1)
Highlighted:hover[data-highlighted]control.bg-hoverPointer and keyboard share one highlight
Frankfurt (fra1)
Selected[aria-selected]currentColorA check alone — no fill, no weight; highlight owns the background
Sydney (syd1) — Pro plan
Disabled[aria-disabled]action.disabled.textVisible but not pickable — vanishing options make state changes illegible
Select · Optional

Starts unset; picking None — the null choice, not a Clear action — returns the trigger to its placeholder. Only an optional select carries it, at the top of the list; an × clear button in the trigger is Combobox's job, since a button cannot nest inside the role="combobox" trigger.

Select · Scroll

Twelve options: the listbox caps at eight dense rows (size.control.sm × 8) and scrolls past the cap. This one is required, so there is no None row — near the fifteen-option mark, start asking whether the list wants to be a Combobox.

Usage notes

Select answers one question: which one, from a list everyone can see.

VerdictRule
DoGive every select a label — visible via FormField, or aria-label when the surrounding context is the label; the placeholder value is not a label.
DoKeep the empty value a hint (text.muted via [data-placeholder]), never essential; pre-select a sensible default when one exists.
DoClear an optional select through a None option at the top of the list — the null choice, never a Clear action row; a required select omits it.
DoDisable individual options sparingly (aria-disabled) and keep them visible — options that vanish make state changes illegible.
DoSet aria-invalid with a message referenced by aria-describedby — never signal errors with color alone.
Don’tReach for Select past a bounded, known list — roughly fifteen options; longer, searchable, async, or free-text entry is Combobox territory (layer 2), and filtering never gets bolted onto a select.
Don’tPut action rows in a listbox — a row that does something on pick belongs in Menu.
Don’tMulti-select with a select — that needs checkboxes, or a layer-2 Combobox with tags.