Role Widget
switch
Marks an element as an on/off switch. Functionally close to a checkbox, but announced as "switch, on" or "switch, off" rather than "checked" — better matches a settings toggle. There is no native HTML equivalent yet.
When to use
For a binary settings control where “on” and “off” describe the state better than “checked” and “unchecked” — Wi-Fi, dark mode, notifications, airplane mode. There is no native HTML switch element, so you have two valid approaches:
<button type="button" role="switch" aria-checked="false">— preferred, because you inherit native button focus and activation.<input type="checkbox" role="switch">— also acceptable; form submission still works, and the role override changes how assistive tech announces it.
Do not use role="switch" for things that aren’t truly binary. If the action navigates, opens a menu, or starts a process, use button or link.
Keyboard + focus contract
Per the APG switch pattern:
- Tab moves focus to the switch.
- Space toggles
aria-checked. Enter SHOULD also toggle (the APG recommends both, since users expect button-like behaviour from a button-based switch). - Focus stays on the switch after toggling.
aria-checked only takes "true" or "false" on a switch — "mixed" is invalid here.
Common failures
role="switch"withoutaria-checkedon first render. The state is required.aria-checked="mixed"on a switch. Only valid for checkbox.- Using
aria-pressedinstead ofaria-checked.aria-pressedbelongs on a toggle button (mute/unmute), where the button performs an action. A switch represents a setting state. - A switch that does not update
aria-checkedwhen toggled via CSS only. - Tiny switch hitboxes that fail WCAG 2.5.8 Target Size. The interactive area must reach 24x24 CSS pixels.
Example
<button
type="button"
role="switch"
aria-checked="false"
onclick="
const next = this.getAttribute('aria-checked') === 'true' ? 'false' : 'true';
this.setAttribute('aria-checked', next);
"
>
Dark mode
</button>