Roles need their required states and properties
- Rule:
axe/aria-required-attr - Checks: Required ARIA attributes must be provided
- WCAG: 4.1.2
- Fix class:
mechanical: A fix needs no authored text or visual decision.
Who it affects
Section titled “Who it affects”- People who use a screen reader or a braille display, most of them blind.
How to fix it
Section titled “How to fix it”A custom checkbox, radio button, switch or checkable menu item has no aria-checked
Section titled “A custom checkbox, radio button, switch or checkable menu item has no aria-checked”Set aria-checked to "true" or "false", or "mixed" for a partly checked checkbox, and update it from script whenever the state changes. A native <input type="checkbox"> or <input type="radio"> needs none of this.
<button type="button" role="switch" aria-checked="false">Wi-Fi</button>A combobox has no aria-expanded, or no aria-controls while expanded
Section titled “A combobox has no aria-expanded, or no aria-controls while expanded”Set aria-expanded to "false" while the popup is closed and "true" while it is open, and point aria-controls at the popup’s id.
<label for="city">City</label><input id="city" type="text" role="combobox" aria-expanded="false" aria-controls="city-options" aria-autocomplete="list"><ul id="city-options" role="listbox" aria-label="Cities" hidden></ul>A slider, scrollbar, meter or focusable separator has no aria-valuenow
Section titled “A slider, scrollbar, meter or focusable separator has no aria-valuenow”Set aria-valuenow to the current number, with aria-valuemin and aria-valuemax for the range, and keep it in step as the value changes. Add aria-valuetext where the number alone means little, such as “Medium”; axe excuses a slider that has only aria-valuetext, but ARIA still requires aria-valuenow.
A <div> or <span> has role="heading" but no aria-level
Section titled “A <div> or <span> has role="heading" but no aria-level”Use a native <h1> to <h6> instead. If the role must stay, add aria-level with the heading’s place in the outline.
Fixes that fail
Section titled “Fixes that fail”Setting the attribute once and never updating it
Section titled “Setting the attribute once and never updating it”axe checks only that the attribute is there, so people can hear a state that contradicts the screen, such as “not checked” on a switch that is on.
Changing the role to one with no required state, such as role="button" for a checkbox
Section titled “Changing the role to one with no required state, such as role="button" for a checkbox”The rule passes, but people can no longer tell whether the option is on or off.
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 state attribute is bound to a value that can be undefined, such as an optional prop
Section titled “A state attribute is bound to a value that can be undefined, such as an optional prop”React leaves out an aria-* attribute whose value is undefined or null, so a switch whose state is not yet set renders with no aria-checked. Default the state to a boolean, such as useState(false) or checked = false among the props; React writes booleans as the "true" and "false" ARIA expects.
import { useState } from 'react';
function WifiSwitch() { const [on, setOn] = useState(false); return ( <button type="button" role="switch" aria-checked={on} onClick={() => setOn(!on)}> Wi-Fi </button> );}Fixes that fail in React
Section titled “Fixes that fail in React”Writing aria-checked={checked || undefined} to drop the attribute when it is false
Section titled “Writing aria-checked={checked || undefined} to drop the attribute when it is false”React then removes aria-checked whenever the switch is off, so the role lacks its required state, and people never hear “off”.
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.