Select menus need a label
- Rule:
axe/select-name - Checks: Select element must have an accessible name
- WCAG: 4.1.2
- Fix class:
content: A fix needs authored text.
Who it affects
Section titled “Who it affects”- People who use a screen reader or a braille display, most of them blind.
- People who control the page by speaking.
How to fix it
Section titled “How to fix it”The first option, such as “Choose a country”, stands in for the label
Section titled “The first option, such as “Choose a country”, stands in for the label”Add a visible <label> connected with for and id. The first option is a value, not a name, and it disappears from view once people choose.
<label for="country">Country</label><select id="country" autocomplete="country"> <option value="">Choose a country</option> <option value="CA">Canada</option> <option value="MX">Mexico</option></select>Visible text names the select but is not connected to it
Section titled “Visible text names the select but is not connected to it”Make the text a <label> whose for matches the select’s id, and keep that id unique on the page.
Several selects share one visible label, such as a date split into month and year
Section titled “Several selects share one visible label, such as a date split into month and year”Group them in a <fieldset> whose <legend> holds the shared label, and give each select its own <label> for its part.
<fieldset> <legend>Card expiration date</legend> <label for="exp-month">Month</label> <select id="exp-month" autocomplete="cc-exp-month"> <option>01</option> <option>02</option> </select> <label for="exp-year">Year</label> <select id="exp-year" autocomplete="cc-exp-year"> <option>2026</option> <option>2027</option> </select></fieldset>Fixes that fail
Section titled “Fixes that fail”Naming the select only with aria-label where a visible label would fit
Section titled “Naming the select only with aria-label where a visible label would fit”Screen readers announce it, but sighted people see no label once a value is chosen, and voice control users cannot tell what to say.
Adding only a title attribute
Section titled “Adding only a title attribute”axe accepts it, but it appears only on mouse hover, so most people never see it. axe’s best-practice rule label-title-only reports it.
In React
Section titled “In React”The part of the fix that differs in React, in its syntax. The rest of the guidance holds.
A select component hard-codes its id or renders its label as plain text
Section titled “A select component hard-codes its id or renders its label as plain text”Render a <label> whose htmlFor is the caller’s id or one from useId, and give the <select> the same id, set after spreading the other props.
function SelectField({ label, options, id: idProp, ...rest }) { const generatedId = useId(); const id = idProp ?? generatedId; return ( <> <label htmlFor={id}>{label}</label> <select {...rest} id={id}> {options.map((option) => ( <option key={option.value} value={option.value}> {option.label} </option> ))} </select> </> );}More on the rule
Section titled “More on the rule”axe-core’s documentation of the rule
CORA’s fix guidance adapts content from accessibility-agents, under the MIT License: see its notice.