Visual design note
-moz-appearance: none; does not completely remove the styling
from the checkbox in Firefox ESR. (works as expected in Firefox 60+).
box-shadow to provide an outline of the control does not
render as expected in IE11, but works as expected in Edge.
IE and Edge don't respect the box-shadow in High Contrast mode. In this mode, the
::-ms-check is re-enabled so that people will at least see a checkmark when the switch is on, and an empty oval when off.
<!-- Version: [type="checkbox"] styled to look like a switch --> <label class="check-switch" for="switch_1"> Example Text 1: <input id="switch_1" type="checkbox"> <span aria-hidden="true"></span> </label> <!-- Version: [type="checkbox"][role="switch"] --> <label class="check-switch" for="switch_2"> Example Text 2: <input id="switch_2" data-check-switch="" role="switch" type="checkbox"> <span aria-hidden="true"></span> </label> <!-- Version: [type="checkbox"][role="switch"] - Alternate Markup/Style --> <div class="switchbox"> <label for="switchbox"> Example Text 3: </label> <input id="switchbox" data-check-switch="" role="switch" type="checkbox"> </div>
Similar to the styled checkbox pattern, similarly a checkbox can be used to create a custom switch control. It should be noted that a form control with the role of
switch vs a
checkbox role have different expectations to screen reader users.
Even if visually styled to resemble a switch, if a native checkbox is used without the
role="switch", the component should continue to function like a checkbox. Meaning that the "switch" should not change the state of a component or alter a global site or application setting, until after a user submits a form the "switch" is a child of. A
role="switch" should be applied to the native checkbox if activating the form control will perform an instant state change, without the need for a form submission.
If implementing visually styled switches within your project, they should be consistently implemented for each usage. Meaning that if a checkbox is visually designed to look like a switch (but continued to be announced as a checkbox), then there should be no instances where the same design is used for a
role="switch". This would create confusion in why two similar looking controls are announced differently (for sighted users who also may use screen readers), or perform actions immediately or delayed until form submission.
data-check-switch attribute as a hook, an
input with this attribute will receive a
The script also allows for the Enter key to be used to toggle the state of the switch, as checkboxes would otherwise only allow for the Space key to toggle their state.
Affects on Screen Reader Announcements?
input type="checkbox" a
role="switch" announces the form control as a "switch" or "toggle button" to screen readers that support the role, and indicate the element's state as either "on/checked" or "off/not checked".
Unfortunately, there are still some gaps in support for this
- JAWS 2019 + Firefox 65.0.1 & Chrome 72
Announces as a "switch". Each announce "on" and "off" when toggling state. Chrome alone will announce "pressed on" for the on state.
- Narrator & Edge
Announces as a "toggle switch". Announces "on" and "off" when toggling state.
- VoiceOver + Safari on iOS 11.3, 11.4, 12.0, & 12.1.4
Unfortunately mobile VoiceOver doesn't understand
role="switch"and will fallback to announcing the component as a "checkbox". However, this fallback is bugged, as the state of the checkbox will not be announced to users on toggle of the component.
- Narrator & NVDA 2018.4.1 + IE11
This pairing will ignore the
role="switch", and continue to announce the component as a checkbox. Checkbox state will be accurately announced on toggle.
- JAWS 2018 & 2019 + IE11
This pairing will announce the form control as a
role="switch", but is inconsistent with announcing the state of the component. Largely only announcing state on a user first focusing the form control with by the virtual cursor navigation or tab key. If activating the form control repeatedly, focus will be lost and return to an element higher up in the DOM.
- NVDA 2018.4.1 + Chrome 72
role="switch"is announced as a "toggle button." Toggling announces as "pressed checked" and "not pressed" for their respective states.
- NVDA 2018.4.1 & 2019.1beta + Firefox 65.0.1
role="switch"is announced as a "toggle button." Toggling announces as "checked" and "not checked" for their respective states.
If "pressed" NVDA will announce initial state as "toggle button not pressed, checked". Toggling state will only announce "not checked" and "checked". (Open bug)
- TalkBack 7.2 (on Android 8.1) + Firefox 64.0.2 & Chrome 71
Announces as a "switch." Toggling announces as "checked" and "not checked" for their respective states.
NVDA 2018.1 and 2018.2.1 notes
These versions of NVDA paired with FireFox and Chrome will announce elements with
role="switch" as "not pressed" and then announce whether they are checked or not.
It doesn't matter the current state of whether the switch is checked or not, with this version of NVDA the switch would always announce "not pressed."
This issue appears to have been fixed after testing with NVDA 2018.4.1.
Until issues with
role="switch" have been worked out, it may be better to use a
button element, with state indicated by
aria-pressed="true/false". Or stick with a
input type="checkbox" if the usage of a checkbox would be an expected user experience.
It's important to remember that switches have an expectation to perform an instant update or change to a user's settings or the UI of an application. It's best to leave checkboxes visually styled to look like checkboxes when in the context of a form, where a change wouldn't be expected until form submission.