skip to content
menu
components · select

select

A select lets people pick one value from a list, such as a region or how long to keep backups. It is a native element: the browser draws the list, and a small blue arrow marks the box.

when to use

  • To pick exactly one value from a known list that is too long to show at once: a region, how long to keep something, a sort order.
  • In a form, inside a field, which gives it its label and its hint.
  • When the list stays the same and people recognise their option by its name.

when to use something else

  • For two or three options that should stay in view. Show them all, as a group of the browser's own radio buttons; today the system has no radio button component of its own. See forms and settings.
  • For on and off. Use a switch when the change applies at once, or a checkbox in a form that is saved. Both show the state at a glance and change it with one press, where a select hides it behind a list.
  • To pick several values. Use a group of checkboxes. A select holds one value only.
  • To filter a list or a table. Use the filter bar, which keeps the search, the filters and the count of what is left together.
  • To switch between views of one page. Use tabs, which show the name of every view at once.
  • For a long list that people need to search. A select only jumps to the option that starts with the letters people type, and today there is no list people can search in. Let people type the value in an input, and check it.

anatomy

  1. Box. A square with a thin border on a dark fill, in one of three heights. It fills the width of its container, and keeps room on the right so the value never runs under the arrow.
  2. Value. The option that is chosen, in monospace.
  3. Arrow. A small blue arrow near the right edge. It is only decoration: assistive technology skips it, and it can't be clicked.
  4. List. The options, drawn by the browser and the operating system. Where the browser allows it, they show as light text on a dark panel.

variants and states

A select comes in three heights, small, medium and large: the same three as an input and a button, so they line up in a row. Medium is the usual one.

state looks
At rest A thin grey border
Focused A thicker blue border, whenever the select has focus, from the mouse or the keyboard
Invalid A red border, which stays while the select has focus
Disabled Dimmed. It can't take focus, be changed or be sent with the form

A disabled option stays in the list, but people can't choose it.

behaviour

  • The browser and the operating system draw the list and decide what the keys do, so the details differ from one platform to another. A select is one tab stop.
  • Choosing an option only sets the value. Don't go to another page, send the form or delete anything when the value changes: on some platforms the up and down arrow keys change the value without opening the list, so someone using the keyboard would set it off just by looking through the options.

Today: only the part of the box that holds the text is the browser's own control. A click on the arrow, or on the space around the value, doesn't open the list.

The full keyboard map is on the select's React page.

accessibility

  • Because it is the browser's own control, the browser tells a screen reader what it is, its value and its options.
  • Give it a visible label. A field adds one, and the label becomes the select's name.
  • Say in words what is wrong. An invalid select only turns its border red; a field's error message says why.
  • Say why an option is disabled, when the reason matters, in the option's own words: “1 year (needs more storage)”.

Today: there are no styles for forced colours, the high-contrast setting some operating systems offer. A select shows focus with a border colour and a shadow inside the box, and forced colours override both, so a select with focus can look as if it had none.

content

  • Label. A noun for the value, in sentence case: “Region”, “Keep backups for”. Not “Select a region”: the control already shows how it works.
  • Options. Short, lowercase and written the same way: “7 days”, “30 days”, “90 days”. Order them by size, by time or by how often people choose them; alphabetically only when there is no natural order.
  • The value it starts with. Choose the safe or the most common value in advance. When there is none, start with an empty option such as “choose a region”, and make the choice required, so the form can't be sent without one.

do and don't

do
Short options, written the same way, in a natural order.
don't
Sentences as options are slow to scan and hard to compare.
do
On or off is a switch: one press, and the state is always in view.
don't
A select with on and off hides the state behind a list, and takes two steps to change.
  • Field: the label, hint and error around the select.
  • Input: free text, when the values aren't known in advance.
  • Checkbox: several values, or a single yes or no in a form.
  • Filter bar: selects and a search that filter a list.

specs

size in code height padding, left padding, right value
Small selectSize="sm" 28px 8px 28px 13px
Medium selectSize="md" (the default) 34px 12px 32px 13px
Large selectSize="lg" 42px 16px 36px 14px
state in code looks
At rest The default A 1px --border-control border on --bg-2
Focused :focus-within, on any focus, by mouse or keyboard A --cloud-blue border and a 1px inset shadow in the same colour: 2px in all
Invalid invalid, which sets aria-invalid="true"; a field's error sets it for you A --state-error border; with focus, the border and the inset shadow both in --state-error
Disabled disabled 50% opacity and a not-allowed cursor; can't be focused, changed or submitted
  • Box: square (border-radius: 0), width: 100%, so set the width on its container. Border colour and shadow change in 120ms ease. The native <select> fills the space between the paddings; the paddings and the arrow are outside it, which is why a click there doesn't open the list.
  • Value: JetBrains Mono, 13px (14px in large), line-height 1.4, in --fg.
  • Arrow: a 12px chevron SVG in --cloud-blue, 12px (--s-3) from the right edge, in an aria-hidden span with pointer-events: none.
  • List: native. Where the browser allows it, the options are --fg on --surface.
  • Options: options, an array of { label, value, disabled? }, or <option> children. When both are given, options wins. A disabled option is disabled and stays in the list.
  • No value yet: an empty first option, value: '', with required on the select.
  • Why selectSize: size is already a native attribute of <select>, the number of rows shown at once.
  • Radio group: for two or three options, a native <fieldset> with <input type="radio">; there is no radio component.
  • Forced colours: no forced-colors styles today. Focus is a border colour and an inset shadow, which forced colours override.