Select
Select lets users choose a single option from a predefined list, presented as a closed field that expands into a menu on interaction.
Select renders a native <select>.
Show code
import { Select } from '@volvo-cars/react-forms';
export function SelectBasic() { return ( <Select name="model" label="Car model"> <option value="ex30">EX30</option> <option value="ex90">EX90</option> <option value="xc40">XC40</option> <option value="xc60">XC60</option> <option value="xc90">XC90</option> <option value="xc70">XC70</option> </Select> );}Floating label
Section titled “Floating label”Use variant="floating-label" to place the label inside the field, floating up when an option is selected.
Validation
Section titled “Validation”Pass errorMessage to display an error and mark the field invalid. The error is hidden when the field is disabled. Use aria-invalid to force the invalid state without a message.
Empty first option
Section titled “Empty first option”By default, Select renders a hidden placeholder option with value="" using the field’s label as text. This prevents the browser from silently pre-selecting the first real option.
To customise the placeholder, or opt out of this behaviour, pass an <option value=""> child yourself:
<Select name="model" label="Car model"> <option value="">Pick a model</option> <option value="xc40">XC40</option></Select>Custom styled select
Section titled “Custom styled select”Adding className="custom-select" opts into a fully design-system-styled picker built on appearance: base-select. This is opt-in and progressive: browsers that don’t yet support appearance: base-select fall back to the default native select with no visual degradation.
On mobile the picker opens as a bottom sheet sliding up from the bottom of the viewport with a scrim overlay. On wider screens it reverts to an anchored dropdown positioned near the field.
Accessibility
Section titled “Accessibility”Key responsibilities from the WCAG audit:
- Always provide a label:
Selectrequires alabelprop. Never omit it. - Error association:
errorMessageautomatically setsaria-invalidand wiresaria-errormessage. Don’t set these manually when using the prop. - Status messages: VoiceOver in Safari has a known issue announcing validation errors on selects. Test with multiple screen readers.
| Prop | Type | Required | Default |
|---|---|---|---|
variant | "top-label" | "floating-label" | - | top-label |
required | boolean | - | - |
| Makes the select required. | |||
enterKeyHint | "done" | "go" | "next" | "previous" | "search" ... | - | - |
| Hint the browser about what label to show for the Enter button on mobile keyboards. | |||
name | string | ✓ | - |
| The name of the input to use when submitting the form. | |||
label | string | ✓ | - |
| A concise label for the input. | |||
autoComplete | "off" | "on" | "organization-title" | "organiza... | - | - |
| What type of information to autocomplete in the select. @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete | |||
errorMessage | string | - | - |
| Set the error message of a select and mark it invalid. | |||
aria-invalid | boolean | - | false |
| Force the input to be invalid. | |||
defaultValue | string | string[] | - | - |
| Default value of an uncontrolled input. | |||
value | string | string[] | - | - |
| Value of the input. Makes the input controlled. | |||
onChange | ChangeEventHandler<HTMLSelectElement, Element> | - | - |
| Fires when the select’s value is changed. | |||
hidden | boolean | - | - |
id | string | - | - |
title | string | - | - |
dir | string | - | - |
lang | string | - | - |
slot | string | - | - |
translate | "yes" | "no" | - | - |
className | string | - | - |
style | CSSProperties | - | - |
tabIndex | number | - | - |
onPointerDown | PointerEventHandler<Element> | - | - |
onPointerEnter | PointerEventHandler<Element> | - | - |
onPointerLeave | PointerEventHandler<Element> | - | - |
onPointerMove | PointerEventHandler<Element> | - | - |
onPointerUp | PointerEventHandler<Element> | - | - |
disabled | boolean | - | false |
| Disables the input. Use sparingly as it can be non-obvious to users why an input has been disabled. Prefer showing validation messages and hints instead. | |||
autoFocus | boolean | - | false |
| Gives the input focus on page load. Use sparingly as it can be confusing to screen-reader and mobile users. | |||
readOnly | boolean | - | false |
| Makes the input read-only. Use sparingly, it's often preferred to present the data as regular text or in a table instead. | |||
form | string | - | - |
| Id of a form element that this input should be associated with. Defaults to the containing form element. | |||
hint | ReactNode | - | - |
| Additional hint or description. | |||
aria-describedby | string | - | - |
aria-labelledby | string | - | - |
onInvalid | FormEventHandler<HTMLSelectElement> | - | - |
| Fires if the input fails validation on form submit. | |||
onFocus | FocusEventHandler<HTMLSelectElement> | - | - |
onBlur | FocusEventHandler<HTMLSelectElement> | - | - |
onKeyDown | KeyboardEventHandler<HTMLSelectElement> | - | - |
onKeyUp | KeyboardEventHandler<HTMLSelectElement> | - | - |