/// Inputs
Select
Input-styled trigger plus an overlay panel for choosing one value from a list; flat or compound API.
import { Select } from "@protocore/pds";Basics
The one-prop form: pass options and Select renders the trigger and panel for you. Controllable via value / defaultValue / onValueChange.
Groups & separators
Drop to the compound API — Select.Root, Trigger, Content, Group, Label, Separator, Item — when you need captioned groups or custom item content.
In a Field, invalid
Set invalid for the danger border and aria-invalid. Pair with a Field error to announce the message. Trigger height follows size (sm · md · lg).
When to use it
Use Select for choosing one value from a known, moderate list (roughly 5–30 options) that doesn't need to stay on screen. When the list is short and worth showing in full, a RadioGroup saves a click; when it's just 2–4 modes, use SegmentedControl. When the list is long or benefits from type-ahead filtering, reach for Combobox instead. For selecting *many* values, use a multi-select FilterBar or a set of Checkboxes.
Usage
Do
- Give the trigger an accessible name via a `Field` label or `aria-label`.
- Provide a `placeholder` when there's no sensible default selection.
- Use `Select.Group` + `Select.Label` to structure long option lists.
- Keep option `value`s stable and non-empty — Radix disallows an empty string value.
Don't
- Don't use Select when users need to filter by typing — use Combobox.
- Don't cram 2–3 options into a Select — a SegmentedControl or RadioGroup reads faster.
- Don't put interactive controls (buttons, links) inside a `Select.Item`.
- Don't leave the trigger unlabelled when no visible field label wraps it.
Accessibility
| Keys | Action |
|---|---|
| Space / Enter / Arrow Down | Open the panel from the focused trigger. |
| Arrow Up / Down | Move between options while open. |
| Enter | Select the highlighted option and close. |
| Type a letter | Jump to the next option starting with that character. |
| Esc | Close the panel without changing the value. |
- Built on Radix Select — the panel is portalled, focus is trapped while open, and focus returns to the trigger on close.
- The trigger exposes `aria-expanded`; the active option carries `aria-selected` with a check indicator.
- `invalid` sets `aria-invalid` on the trigger for assistive tech.
Select props
| Prop | Type | Default | Description |
|---|---|---|---|
aria-describedby | string | — | Ids of elements describing the trigger (e.g. a `<Field>` hint/error). |
aria-label | string | — | Accessible label for the trigger when no visible `<Field>` label wraps it. |
aria-labelledby | string | — | Ids of elements labelling the trigger (e.g. a `<Field>` label). |
className | string | — | Class applied to the trigger. |
defaultValue | string | — | |
id | string | — | Id applied to the trigger button — wired automatically when wrapped in `<Field>`. |
invalid | boolean | — | Mark the trigger invalid. |
onValueChange | ((value: string) => void) | — | |
options * | SelectOption[] | — | Options to render; use the compound API instead for groups or custom item content. |
placeholder | ReactNode | — | Placeholder shown when no value is selected. |
size | enum | md | Trigger height. |
value | string | — |
SelectTrigger props
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | — | |
className | string | — | |
invalid | boolean | — | Mark the trigger invalid — danger border plus `aria-invalid`. |
size | enum | md | Trigger height: `sm` (32) · `md` (36, default) · `lg` (40). |
style | CSSProperties | — |
SelectItem props
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | — | |
className | string | — | |
style | CSSProperties | — |