Who it affects
Someone using a screen reader lands on a dark mode toggle and hears switch with no on or off. They cannot tell what will happen if they press it.
Someone using a braille display reads swch and nothing more, with no state cell beside it.
Someone using switch access or a sip-and-puff device with a screen reader has to activate the control blind, then listen again, then possibly undo it, which is three slow actions instead of one.
Broken versus fixed
Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.
The toggle is clearly on. A screen reader announces: Dark mode, switch, off, or just Dark mode, switch. Without aria-checked the browser has no state to report and may guess.
Announced: Dark mode, switch, on. In a real page your script flips aria-checked each time the button is pressed; this demo is static.
Show the markup behind both examples
<style>body{font-family:system-ui;padding:16px;margin:0}.row{display:flex;align-items:center;gap:12px}.sw{width:44px;height:24px;border-radius:12px;border:0;background:#2b6cb0;position:relative;padding:0;cursor:pointer}.sw::after{content:"";position:absolute;top:3px;left:23px;width:18px;height:18px;border-radius:50%;background:#fff}</style>
<div class="row">
<span id="dm">Dark mode</span>
<button class="sw" role="switch" aria-labelledby="dm"></button>
</div>
<style>body{font-family:system-ui;padding:16px;margin:0}.row{display:flex;align-items:center;gap:12px}.sw{width:44px;height:24px;border-radius:12px;border:0;background:#2b6cb0;position:relative;padding:0;cursor:pointer}.sw::after{content:"";position:absolute;top:3px;left:23px;width:18px;height:18px;border-radius:50%;background:#fff}</style>
<div class="row">
<span id="dm">Dark mode</span>
<button class="sw" role="switch" aria-checked="true" aria-labelledby="dm"></button>
</div>
Test it by hand in two minutes
- Inspect the element with the role attribute and list its aria- attributes.
- Check the role's required attribute is there: switch and checkbox need aria-checked, slider and spinbutton need aria-valuenow, heading needs aria-level, combobox needs aria-expanded, scrollbar needs aria-controls and aria-valuenow.
- Turn on VoiceOver (Cmd+F5) or NVDA, Tab to the control and listen for the state after the role: on or off, a number, a level.
- Operate the control and listen again. The state should change in the announcement, not just on screen.
The fix
<button role="switch" aria-labelledby="dm"></button>
<button role="switch" aria-checked="true" aria-labelledby="dm"></button>
Add the attribute and keep it updated in the same place your code changes the visual state. If you would rather not manage state by hand, a native input type="checkbox" with role="switch" handles aria-checked for you.
Slider without a value
<div role="slider" aria-label="Volume" tabindex="0"></div>
<div role="slider" aria-label="Volume" aria-valuemin="0" aria-valuemax="100" aria-valuenow="40" tabindex="0"></div>
aria-valuenow is required. aria-valuemin and aria-valuemax default to 0 and 100 but stating them avoids surprises. A native input type="range" does all of this.
Heading role without a level
<div role="heading">Delivery</div>
<h2>Delivery</h2>
role="heading" needs aria-level. Usually the better fix is a real h2 or h3, which carries the level for free.
Common mistakes
- Adding the attribute with a fixed value and never updating it, so it is always on or always 50.
- Putting aria-checked on the label span instead of the element that has the role.
- Writing aria-checked="checked" or aria-valuenow="40%"; the values must be true or false, or a plain number.
- Removing the role to silence the finding, which turns the switch into an unnamed button.
- Building a switch, slider or spinbutton from divs when a native input would carry its own state.
WCAG criteria this rule maps to
axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:
- 4.1.2 Name, Role, Value (level A). Official W3C text.
The scanner knows which attributes each role requires and can see when one is absent. It cannot see whether the attribute is kept up to date when the control is used, so check that by hand. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.
Related rules
aria-allowed-attr
Every ARIA role comes with a short list of attributes it understands.
A
ARIA attributes must have valid values
aria-valid-attr-value
Each ARIA attribute accepts a particular kind of value: true or false, a number, a word from a short list, or the id of another element.
A
ARIA toggle fields must have an accessible name
aria-toggle-field-name
Elements with role="switch", role="checkbox", role="radio", role="menuitemcheckbox" or role="menuitemradio" are toggles: they are on or off, checked or not.
A
ARIA input fields must have an accessible name
aria-input-field-name
When a div or span is given a form role such as textbox, combobox, listbox, slider or spinbutton, assistive technology treats it as a field.