Select
One value from a list, shown in the field once it is chosen: a button in Input’s box that opens the system’s own list.
Try it
An Avatar before the name, a code in bold, a plain list with an icon: the three drawn fields. Type a letter, open or closed, to go to an option.
Choosing a select
A select is for one value from a list too long to lay out: past six or so options, a row of radios is a wall, and a select is one line. Under that, prefer radios, which show every answer at once and need no opening. Two answers are a switch or a checkbox, never a select.
Put the options in the order the reader expects — alphabetical for names and places, by size or by time where the list has one, and the common answer first when there is one — and choose it for them when the form usually wants it. A placeholder is a prompt for the field’s answer, Choose a service: it is not an option, and it cannot be the value a required field submits.
Select or dropdown menu
Both are a button that opens a list on the same surface, and in a drawing they are the same thing. They answer different questions. A select holds a value: the choice stays visible in the field afterwards, belongs to a form, and is submitted with it. A dropdown menu runs a command: nothing is kept, the list closes, and something happens — reschedule, export, cancel.
The test is what the control shows once the list has closed. If it shows the choice, it is a Select. If choosing was the end of it, it is a dropdown menu. A screen reader is told the difference: a select says its name, its value and “3 of 12”; a menu says how many commands it has.
Chosen, and active
The chosen option carries a check in the accent and nothing else. The wash belongs to the active option, the one under the pointer or the arrows, so the two are never the same mark, and when they are the same option both show. The check is a shape, so the choice does not rest on colour.
Anatomy and sizes
| Part | Value |
|---|---|
| Field | Input’s box: 32, 40 or 48 tall, radius 12 |
| Chevron | 20, in the accent |
| List | the menu’s surface, radius 12, 8 of padding, never narrower than the field |
| Option | 40 tall, radius 6; taller with a description |
| Description | 12 / 16 |
| Check | 16, in the accent |
| Most | eight options, then it scrolls |
The field is Input’s box, at its three heights, with the same fill and the same border that arrives on focus. The open list is not drawn anywhere; it is the menu’s rows on the one floating surface the menu, the date picker and the popover stand on.
States
No hover, as on Input: the box does not react to the pointer, and the border arrives with focus. Disabled drops the paint and the focus; invalid takes the danger border, and inside a Field the message that says what to choose.
In a Field
The Field’s label names the button, and its description and error are read with it. With a name the value goes with the form through a hidden input. A hidden input cannot stop a form, so required is said to a screen reader and enforced by the caller, as the error above is.
The platform’s select
Until 2026-09-21 this component was the native <select>, by a rule the system still holds: prefer the native element. It was set aside here for one reason. The drawn fields hold what a native list cannot show — an Avatar, a code in bold, a second line — and the list belongs to the operating system, so it is a different list in every browser. appearance: base-select will end that trade; it is in Chrome, Edge and Safari 27, and not yet in Firefox.
The native one is NativeSelect, unchanged. It is the better choice on a phone in a long form, where the platform’s picker is better than any list of ours, and for a very long list such as countries.
Accessibility
It is the select-only combobox of the ARIA practices: a button with role="combobox" that owns a listbox. The keyboard’s focus never leaves the button; the active option is named to it, so there is one tab stop and nothing to give the focus back to. The list is the platform’s popover, so a press outside closes it.
| Key | Does |
|---|---|
| Down, Up, Enter, Space | Open the list at the option that is chosen. |
| Down, Up | Move over the options, past what cannot be chosen, and stop at the ends. |
| Home, End | The first and the last. |
| A letter | The next option that starts with it, open or closed. |
| Enter, Space | Choose and close. |
| Tab | Chooses the active option and moves on. |
| Esc | Closes with nothing chosen, and goes no further: a Dialog around it stays. |
The select never renders its own label. Wrap it in a Field or give it an aria-label, as the sizes above do. An option’s label is always words, even where content is shown in its place: it is what typing finds.
Props
import { Select, Avatar, Field } from 'alpenglow';
<Field label="Staff">
<Select
name="staff"
placeholder="Choose someone"
value={staff}
onChange={setStaff}
options={[
{ label: 'On shift', options: people.map((p) => ({
value: p.id,
label: p.name,
start: <Avatar name={p.name} size="xxs" />,
})) },
]}
/>
</Field>| Prop | Type | Default |
|---|---|---|
options | Select | required |
value | string | — |
defaultValue | string | '' |
onChange | (value: string) => void | — |
placeholder | string | — |
size | 'sm' | 'md' | 'lg' | density/control — 40, 32 compact |
invalid | boolean | from Field, else false |
disabled | boolean | false |
required | boolean | from Field |
name | string | — |
iconStart | React | — |
id, aria-label, aria-labelledby, aria-describedby | string | from Field |
className | string | — |
| Field | Type | Default |
|---|---|---|
value | string | required |
label | string — what typing finds and a screen reader says | required |
start | React | — |
description | string | — |
content | React | — |
disabled | boolean | false |
A group is { label, options }. NativeSelect takes size, placeholder, invalid, iconStart, its options as children, and every attribute of a select.