Switch Role Support
Whether you use a <button>
or <input type="checkbox">
as the basis for your switch depends on a few factors:
- Use
<button>
if:- you can count on JavaScript being available, and
- flipping the switch has an immediate effect.
Go read Under-Engineered Toggles Too.
- Use
<input type="checkbox">
if:- you want to progressively enhance the control, and
- flipping the switch will only take effect when the user submits it.
Go read Under-Engineered Toggles.
Those two posts show you how to accessibly style your pill-like controls. Whether you follow any of that advice, use any of those styles, or ignore it all completely is mostly irrelevant from here out. All this post cares about is what happens once you add the switch
role.
Normally, both aria-checked
and aria-pressed
allow for a mixed
value. With the switch
role, however, you are restricted to aria-checked
and only the values true
or false
. The mixed
value is invalid on the switch
role in the current ARIA spec and into the ARIA 1.3 Editor’s Draft.
The
aria-checked
attribute of aswitch
indicates whether the input is on (true
) or off (false
). Themixed
value is invalid, and user agents MUST treat amixed
value as equivalent tofalse
for this role.
Test Case
As always, the example pen is available in debug mode for you to test with your favorite assistive technology. You should do that, especially since these results will be out of date as soon as a new release of anything comes out. I also did not test with voice control, though it generally cares little for ARIA.
There are no styles other than to indicate the buttons’ states. This post only cares about how the controls are exposed to screen reader users through the browser’s accessibility tree.
See the Pen Toggles by Adrian Roselli (@aardrian) on CodePen.
Testing
None of ARC, Axe, or Wave flag a mixed
value when used with a switch
role. Neither does the HTML validator. See my post Beware False Negatives for why I bother to mention this.
I left the screen reader instructions for each control in the following output. It is interesting to see how the instructions change depending on control types and roles.
Chrome 94–106 with JAWS 2021–2022
Chrome exposes aria-checked="mixed"
on a switch
role as “true”, which is against the specification. Interaction instructions are not offered for the switches (you do not need to provide them). Generally unrelated to this post, be careful using aria-checked
on a native checkbox, as Scott O’Hara notes in a Chromium bug report.
- Checkbox
- Hammer check box checked. To clear check mark press Spacebar.
- Sandwich check box not checked. To check press Spacebar.
- Animal check box partially checked. To check press Spacebar.
- Button with
aria-pressed
- Hot Dog Toggle button Pressed. To toggle the state press spacebar.
- Drill Toggle button. To toggle the state press spacebar.
- Vegetable Toggle button partially checked. To toggle the state press spacebar.
- Checkbox with
switch
role- Taco Switch Pressed On.
- Wrench Switch Off.
- Mineral Switch partially checked Off.
- Button with
aria-checked
andswitch
role- Panino Switch Pressed On.
- Pliers Switch Off.
- General Switch Pressed On.
- Checkbox with
switch
role andaria-checked
- Saw Switch Pressed On
- Bao Switch Off
- Model Switch Pressed On
Firefox 93–105 with NVDA 2021.2–2022.3
Firefox exposes aria-checked="mixed"
on a checkbox with the switch
role as “mixed”, which is against the specification. Firefox does not expose the switch
role, always announcing it as a checkbox.
- Checkbox
- Hammer check box checked
- Sandwich check box not checked
- Animal check box half checked
- Button with
aria-pressed
- Hot Dog toggle button pressed
- Drill toggle button not pressed
- Vegetable toggle button not pressed half checked
- Checkbox with
switch
role- Taco check box checked
- Wrench check box not checked
- Mineral check box half checked
- Button with
aria-checked
andswitch
role- Panino check box checked
- Pliers check box not checked
- General check box not checked
- Checkbox with
switch
role andaria-checked
- Saw check box checked
- Bao check box not checked
- Model check box half checked
Narrator (Windows 10–11) with Edge 94–105
Edge exposes aria-checked="mixed"
on a button with the switch
role as “true”. Edge exposes aria-checked="mixed"
on a checkbox with the switch
role as “mixed”. Both of these are against the specification.
- Checkbox
- Hammer check box checked
- Sandwich check box unchecked
- Animal check box indeterminate
- Button with
aria-pressed
- Windows 10
- Hot Dog button on
- Drill button off
- Vegetable button indeterminate
- Windows 11 22H2
- Hot Dog toggle button on
- Drill toggle button off
- Vegetable toggle button indeterminate
- Windows 10
- Checkbox with
switch
role- Taco switch on
- Wrench switch off
- Mineral switch indeterminate
- Button with
aria-checked
andswitch
role- Panino switch on
- Pliers switch off
- General switch on
- Checkbox with
switch
role andaria-checked
- Saw switch on
- Bao switch off
- Model switch on
Narrator (Windows 11) with Firefox 105
This shows how when Firefox is paired with Narrator, Narrator diverges from NVDA when announcing the mixed state for aria-checked
. I gave this a test based on feedback from James Scholes on Twitter.
- Checkbox
- Hammer check box checked
- Sandwich check box not checked
- Animal check box half checked
- Button with
aria-pressed
- Hot Dog toggle button pressed
- Drill toggle button not pressed
- Vegetable toggle button not pressed half checked
- Checkbox with
switch
role- Taco check box checked
- Wrench check box not checked
- Mineral check box half checked
- Button with
aria-checked
andswitch
role- Panino check box checked
- Pliers check box not checked
- General check box checked
- Checkbox with
switch
role andaria-checked
- Saw check box checked
- Bao check box not checked
- Model check box checked
TalkBack 9.1–13 (Android 11–13) with Chrome 94–106
TalkBack with Chrome announces aria-checked="mixed"
on a checkbox with the switch
role as “partially checked”, and on a button with the switch
role as “checked”, both of which are against the specification. Interestingly, TalkBack notes you can toggle all controls, unless they are a checkbox in a mixed state, then you “activate” it.
- Checkbox
- checked, Hammer, checkbox. Double-tap to toggle.
- not checked, Sandwich, checkbox. Double-tap to toggle.
- partially checked, Animal, checkbox. Double-tap to activate.
- Button with
aria-pressed
- on, Hot Dog, toggle button. Double-tap to toggle.
- off, Drill, toggle button. Double-tap to toggle.
- partially checked, Vegetable, toggle button. Double-tap to activate.
- Checkbox with
switch
role- TalkBack 9.1 with Chrome 94
- checked, Taco, switch. Double-tap to toggle.
- not checked, Wrench, switch. Double-tap to toggle.
- partially checked, Mineral, switch. Double-tap to activate.
- TalkBack 13 with Chrome 106
- on, Taco, switch. Double-tap to toggle.
- off, Wrench, switch. Double-tap to toggle.
- partially checked, Mineral, switch. Double-tap to activate.
- TalkBack 9.1 with Chrome 94
- Button with
aria-checked
andswitch
role- TalkBack 9.1 with Chrome 94
- checked, Panino, switch. Double-tap to toggle.
- not checked, Pliers, switch. Double-tap to toggle.
- partially checked, General, switch. Double-tap to toggle.
- TalkBack 13 with Chrome 106
- on, Panino, switch. Double-tap to toggle.
- off, Pliers, switch. Double-tap to toggle.
- on, General, switch. Double-tap to toggle.
- TalkBack 9.1 with Chrome 94
- Checkbox with
switch
role andaria-checked
- on, Saw, switch. Double-tap to toggle.
- off, Bao, switch. Double-tap to toggle.
- on, Model, switch. Double-tap to toggle.
TalkBack 9.1–13 (Android 11–13) with Firefox 93–105
TalkBack with Firefox announces a standard mixed checkbox as “not checked”. It also announces all buttons with aria-pressed
as “switch”, though they do not have that role, and TalkBack does not announce their value.
- Checkbox
- checked, Hammer, check button. Double-tap to toggle.
- not checked, Sandwich, check button. Double-tap to toggle.
- not checked, Animal, check button. Double-tap to toggle.
- Button with
aria-pressed
- TalkBack 9.1 with Firefox 93
- Hot Dog, switch, Hot Dog. Double-tap to activate.
- Drill, switch, Drill. Double-tap to activate.
- Vegetable, switch, Vegetable. Double-tap to activate.
- TalkBack 13 with Firefox 105
- Hot Dog, switch. Double-tap to activate.
- Drill, switch. Double-tap to activate.
- Vegetable, switch. Double-tap to activate.
- TalkBack 9.1 with Firefox 93
- Checkbox with
switch
role- checked, Taco, switch. Double-tap to toggle.
- not checked, Wrench, switch. Double-tap to toggle.
- not checked, Mineral, switch. Double-tap to toggle.
- Button with
aria-checked
andswitch
role- checked, Panino, switch, Panino. Double-tap to toggle.
- not checked, Pliers, switch, Pliers. Double-tap to toggle.
- not checked, General, switch, General. Double-tap to toggle.
- Checkbox with
switch
role andaria-checked
- checked, Saw, switch. Double-tap to toggle.
- not checked, Bao, switch. Double-tap to toggle.
- not checked, Model, switch. Double-tap to toggle.
VoiceOver (iPadOS 14.8–15.7) with Safari 14–15.6
VoiceOver announces a standard mixed checkbox as “unchecked”, and any other control with aria-pressed="mixed"
or aria-checked="mixed"
as “unchecked”. VoiceOver also announces a button with aria-pressed="mixed"
as a checkbox. Finally, VoiceOver announces nothing as a switch. Scott O’Hara filed a WebKit bug in early 2019.
- Checkbox
- Hammer, checkbox, checked. Double-tap to toggle setting.
- Sandwich, checkbox, unchecked. Double-tap to toggle setting.
- Animal, checkbox, unchecked. Double-tap to toggle setting.
- Button with
aria-pressed
- Hot Dog, toggle button, pressed. Double-tap to toggle setting.
- Drill, toggle button, not pressed. Double-tap to toggle setting.
- Vegetable, checkbox, mixed. Double-tap to toggle setting.
- Checkbox with
switch
role- Taco, checkbox, checked. Double-tap to toggle setting.
- Wrench, checkbox, unchecked. Double-tap to toggle setting.
- Mineral, checkbox, unchecked. Double-tap to toggle setting.
- Button with
aria-checked
andswitch
role- Panino, checkbox, checked. Double-tap to toggle setting.
- Pliers, checkbox, unchecked. Double-tap to toggle setting.
- General checkbox, unchecked. Double-tap to toggle setting.
- Checkbox with
switch
role andaria-checked
- Saw, checkbox, checked. Double-tap to toggle setting.
- Bao, checkbox, unchecked. Double-tap to toggle setting.
- Model, checkbox, unchecked. Double-tap to toggle setting.
VoiceOver (macOS 11.4–12.6) with Safari 14.1.1–16
VoiceOver announces a standard mixed checkbox as “unchecked”. Scott O’Hara filed another WebKit bug almost two weeks ago identifying it as a regression. Otherwise Safari/VO handles switch
correctly, and far better than its iOS/iPadOS cousin.
- Checkbox
- Hammer, checked, checkbox, Checkbox. You are currently on a checkbox. To select or deselect this checkbox, press Control-Option-Space.
- Sandwich, unchecked, checkbox, Checkbox. You are currently on a checkbox. To select or deselect this checkbox, press Control-Option-Space.
- Animal, unchecked, checkbox, Checkbox. You are currently on a checkbox. To select or deselect this checkbox, press Control-Option-Space.
- Button with
aria-pressed
- Hot Dog, selected, toggle button, Button with aria-pressed. You are currently on a toggle button. To select or deselect this checkbox, press Control-Option-Space.
- Drill, toggle button, Button with aria-pressed. You are currently on a toggle button. To select or deselect this checkbox, press Control-Option-Space.
- Vegetable, mixed, toggle button, Button with aria-pressed. You are currently on a toggle button. To select or deselect this checkbox, press Control-Option-Space.
- Checkbox with
switch
role- Taco, on, switch, Checkbox with switch role. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
- Wrench, off, switch, Checkbox with switch role. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
- Mineral, off, switch, Checkbox with switch role. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
- Button with
aria-checked
andswitch
role- Panino, on, switch, Button with aria-checked and switch role. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
- Pliers, off, switch, Button with aria-checked and switch role. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
- General, off, switch, Button with aria-checked and switch role. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
- Checkbox with
switch
role andaria-checked
- Saw, on, switch, Checkbox with switch role and aria-checked. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
- Bao, off, switch, Checkbox with switch role and aria-checked. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
- Model, off, switch, Checkbox with switch role and aria-checked. You are currently on a switch. To select or deselect this checkbox, press Control-Option-Space.
Verdict
The switch
role does not allow mixed states. Ensure your switch never gets set to a mixed state, otherwise, well, problems.
Switches do not always announce as switches. It may be worth keeping this in mind for documentation — both for developers and end users.
The best performers for switches are TalkBack 9.1 / Android 11 with Firefox 93 (though buggy with toggled buttons and mixed native checkboxes) and VoiceOver / macOS 11.4 with Safari 14.1.1 (though buggy with mixed native checkboxes). The worst are Firefox 93 with NVDA 2021.2 (it does not announce them as switches, and is wrong with mixed buttons) and VoiceOver / iOS 14.8 with Safari 14 (it does not announce them as switches, and is wrong with mixed buttons and checkboxes).
I am naming these because Safari is both the best (desktop) and the worst (mobile) and Firefox is also both the best (mobile) and the worst (desktop). This should drive home the point that a browser should not be expected to perform the same on mobile and desktop, even for the same version.
If you are trying to figure out which approach is right for you, well, I don’t know. I’m not your dad.
Updated Verdict, 5 October 2022
In the year since I wrote this post, there have been minor changes.
- Narrator on Windows 11 with Edge 105 now announces a button with
aria-pressed
as “toggle”, which is definitely clearer but does not change support. - TalkBack 13 with Chrome 106 now announces both a checkbox and button with the
switch
role as “on” or “off” versus “checked” or “not checked”, which also does not change support. - TalkBack 13 with Chrome 106 now announces button with the
switch
role andaria-checked="mixed"
as “on”, which is still wrong. - TalkBack 13 with Firefox 105 no longer double announces the accessible name of a button with
aria-pressed
, but is still otherwise broken.
In short, things that were broken are still broken. If a switch was not announced as a switch before, it still isn’t (looking at you NVDA/Firefox and VoiceOver/iOS).
Update: 6 October 2022
I added another example which uses aria-checked
on the checkbox. I held off before because the checked
property (or lack thereof) should take priority, but realized it was an incomplete test without it. The native property and the aria-checked
values stay in synch.
I also filed two browser issues:
- Firefox issue 1793880: `switch` role on checkbox with mixed/indeterminate state reports wrong value
- Chromium issue 1372131: `switch` role on checkbox with mixed/indeterminate state reports wrong value
Have not gone back to sort the VO/Safari/iPadOS wonkiness yet.
In the interest of spamming all the issue trackers, I also left a comment on Core AAM #75 Sanity-check mappings for switch role.
Update: 22 December 2023
Safari Technology Preview 185 landed with support for a proposed native switch element. More accurately, it landed with support for:
<input type="checkbox" id="ck01sp" switch checked>
<label for="ck01sp">Pliers</label>
The switch
role has two key differences from a checkbox: it does not allow an indeterminate state but it does allow a required state. Which means I was obligated to update my example above to confirm support in Safari Technology Preview 185.
The good news is that it is exposed correctly and announces as expected (including “on” and “off” versus “checked” and “not checked”):
- Pliers, on, switch
- Arepa, off, switch
- General, off, switch
- Necessary, required invalid data off, switch
For more context, a switch element was propsed with WHATWG HTML in 2018, Google worked on it for a while, along with the some WICG discussion, then abandoned it. Open-UI started a discussion in 2021, but other than a comment on valid indeterminate use cases, has mostly died there.
Then in July 2023 (5 months ago), a new contributor filed a WHATWG PR to add a switch
attribute to a checkbox and here we are. Note that it has not been merged into WHATWG HTML, so Apple Safari has chosen to get way ahead of this one.
The good news is that conversations on Mastodon suggest visual cues are pretty good (such as contrast and honoring color preferences). The less good news is that this feature is not part of the spec yet and, as I noted in my post about allowing <hr>
in <select>
, makes me want a versioned spec versus the shifting one we have now:
Since WHATWG HTML is versionless, and since it essentially only takes one browser implementation to get into WHATWG HTML, and since the people approving PRs to WHATWG HTML seem to be the same ones adding features to Safari and Chrome, perhaps the best way to stay on top of HTML today is to look at Chrome “intent to ship” announcements and Safari feature releases.
Remember how breathless Apple was when it announced it was the first browser to ship this new
? Expect the same here in a few months. While it is indeed swell that Safari flipped a bit to take its existing support for the ARIA <search>l
elementswitch
role and apply it to this element, be wary when it brags about being first.
Anyway, don’t use this in production yet.
One Comment
It’s a nice addition, but the implementation seems a bit rushed. The control doesn’t scale properly and visually breaks when changing the zoom level (e.g., screenshots at 400% and 25% zoom level.)
Leave a Comment or Response