Select
Single-choice field that opens the DS option list (a select-only combobox), with labelled options, statuses, label-row actions and size tokens.
Status: stable. Group: form. Markdown version: /design-system/components/select.md
When to use
Select is the single-choice field. It renders Combobox's select-only combobox inside FieldShell, so it opens the same DS option list as every other dropdown on the site, never the operating system's popup. Feed it an options array or option children (an empty-value option becomes the placeholder) and read changes via onValueChange; pass name to submit with a native form.
Use Select for five or more exclusive options, or when space is tight; RadioGroup is better when all options should stay visible.
When not to use
- Do not ship a Select with
valueanddefaultValueboth set;valuewins and a dev warning fires. - Do not use Select for a freeform value with suggestions; use TextInput.
- Do not render a native <select> beside or inside it; every DS dropdown opens the DS list.
Look-alikes
- RadioGroup: Use Select for five or more exclusive options, or when space is tight; RadioGroup is better when all options should stay visible.
- SegmentedControl: Do not overflow it; if the options do not fit on one line, use
Select. - SelectOption: Use the Select options array for ordinary flat data; use SelectOption children for explicit declarative composition.
- TextInput: Do not use Select for a freeform value with suggestions; use TextInput.
Props
| Prop | Type | Default | Description | Required |
|---|---|---|---|---|
label | string | none | Label text displayed above the select dropdown. | Yes |
options | SelectOptionItem[] | [] | Option objects with value, label, and optional disabled; children override this. | No |
helperText | string | none | Supporting text under the control; always rendered, below error when both are set. | No |
error | string | none | Error message under the control; sets aria-invalid and aria-describedby. | No |
status | FieldStatus | none | Semantic state: colours the border and styles statusMessage. error overrides it. | No |
statusMessage | string | none | Message under the control for status, above the helper line. | No |
actions | FieldAction[] | none | Icon buttons at the end of the label row: each runs an operation or opens a menu. | No |
size | "sm" | "md" | "lg" | "S" | "M" | "L" | md | Size variant for select. | No |
onValueChange | (value: string) => void | none | Value change handler (recommended) | No |
disabled | boolean | false | Disables the select. | No |
onChange | (value: string) => void | none | No description in the contract. Deprecated: Deprecated. | No |
children | React.ReactNode | none | <option> or SelectOption children; an option with value "" becomes the placeholder. | No |
value | string | none | Selected value (controlled); "" shows the placeholder. | No |
defaultValue | string | none | Initial value when uncontrolled. | No |
required | boolean | false | Marks the field required. | No |
id | string | none | Explicit control id (wires the label); auto-generated when omitted. | No |
name | string | none | Submits the value with a surrounding form, through a hidden input. | No |
className | string | none | Classes on the field wrapper. | No |
Variants
- Available sizes:
sm,md,lg,S,M,L(defaultmd). Forwarded to CSS module size classes.
Invalid combinations
- MUST NOT:
valueanddefaultValueset together.valuemakes the component controlled anddefaultValueuncontrolled; pass one, not both.
Keyboard
| Key | Behaviour |
|---|---|
| Tab | Moves focus to and from the field and closes an open list. Focus moving to any element outside the field also closes it. |
| ArrowDown | Skips disabled options. |
| ArrowUp | Skips disabled options. |
| Home | First enabled option. |
| End | Last enabled option. |
| Enter | Activates the focused control. (standard) |
| Space | Activates or toggles the focused control. (standard) |
| Escape | Closes or dismisses the open layer. (standard) |
| General | Type-ahead. |
Rows marked (standard) name a key the contract lists without a description; the behaviour shown is the usual one for that key.
Rules
Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.
| Level | Rule | How it is checked |
|---|---|---|
| MUST NOT | value and defaultValue set together. value makes the component controlled and defaultValue uncontrolled; pass one, not both. | Checked by the MCP tool validate_component_usage. |
| MUST | ARIA: Combobox named by the associated label. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Listbox with aria-selected and aria-activedescendant. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Status message and helper linked with aria-describedby; error announced as an alert. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | Required stories produce no axe violations at the configured severity. | Automated by npm run test:stories:matrix:ci. WCAG 2.5.8. |
| MUST | The accessibility tree (role, name, state) matches the committed snapshot for every required story. | Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2. |
| MUST | The component remains legible and operable under a real browser forced-colors: active pass. | Automated by npm run test:stories:hc. |
| MUST | Every documented keyboard interaction works as specified. | Not yet verified: no evidence record. WCAG 2.1.1, 2.1.2. |
| MUST | A human completed an end-to-end accessibility review of this component. | Manual review, last on 2026-11-04. |
| SHOULD | Lead with an empty placeholder option when there is no safe default, and validate it as unselected. | Not stated in the contract. |
| SHOULD NOT | Do not expect Select to filter a long list as the user types; like Combobox, whose engine it uses, it only moves the highlight to the first typeahead match. | Not stated in the contract. |
| SHOULD | Pass name when the field submits with a native form; a hidden input carries the selected value. | Not stated in the contract. |
| SHOULD NOT | Do not silently preselect a consequential option (billing plans); make the user choose. | Not stated in the contract. |
| SHOULD | Keep option labels short; the list truncates nothing, so long labels wrap and slow scanning. | Not stated in the contract. |
Install and import
- Install:
npm install @digitaltableteur/react(version 0.9.1, restricted access on npm). - Import:
import { Select } from "@digitaltableteur/react"; - Entry point:
@digitaltableteur/react/formsexports it too. - Styles: import
@digitaltableteur/react/style.cssonce at the app boundary. - Also available as the custom element
<dt-select>; see the custom elements manifest.
Links
- Machine-readable contract (Design System Contract 1.0)
- Markdown version of this page
- Component index as JSON
- All components
- Source: The implementation lives in a private repository. This page, its Markdown twin and the contract are generated from it at build time and are the public source of truth.