Switch
A switch is an input widget that allows users to choose one of two values: on or off. Switches are similar to checkboxes and toggle buttons, which can also serve as binary inputs, although both checkboxes and toggle buttons can have three states: on, off, or indeterminate. A switch's state is conveyed to assistive technology users as "checked" or "unchecked" so use a switch when these states will be meaningful to the user.
A switch may be implemented using a semantic HTML checkbox (recommended), a button element with role="switch"
or a
non-semantic element with role="switch"
.
Role
A switch widget must have a role of switch. This is achieved by adding the role="switch"
attribute to the element.
Even if the switch is implemented using a semantic HTML checkbox, the role="switch"
attribute must still be added.
Accessible name
A switch must have an accessible name. The accessible name is the text that is read by screen readers to describe the element. There are many ways to provide an accessible name for a switch. If an HTML checkbox is used, the accessible name should be provided by the checkbox label. The accessible name should convey the functionality of the switch but not the current state of the switch (On/Off).
1<!-- The checkbox label constitutes the switch's accessibility label -->2<label>3 Dark mode4 <input type="checkbox" role="switch" class="on" />5</label>67<!-- The `label[for]` attribute may also be used instead of wrapping8 the input in a label tag -->9<label for="dark-mode">10 Dark mode11</label>12<input type="checkbox" id="dark-mode" role="switch" class="on" />
If the switch is implemented using a button element or a non-semantic element, the accessible name can be provided in a couple of ways:
1<!-- The button text constitutes the switch's accessibility label -->2<button role="switch" aria-checked="false">3 <span class="label">Dark mode</span>4 <span class="on" aria-hidden="true">On</span>5 <span class="off" aria-hidden="true">Off</span>6</button>78<!-- Switch gets its accessibility label from the aria-label attribute -->9<div role="switch" tabindex="0" aria-label="Dark mode" aria-checked="false">10 <span class="on" aria-hidden="true">On</span>11 <span class="off" aria-hidden="true">Off</span>12</div>1314<!-- Switch gets its accessibility label from the aria-labelledby attribute -->15<span id="dark-mode-label">Dark mode</span>16<div role="switch" tabindex="0" aria-labelledby="dark-mode-label" aria-checked="false">17 <span class="on" aria-hidden="true">On</span>18 <span class="off" aria-hidden="true">Off</span>19</div>
Focus sequence
A switch must be focusable unless it is disabled. This is important for keyboard users who need to be able to navigate to the switch.
Semantic HTML inputs and buttons are always focusable when not disabled. Switches implemented using non-semantic elements
can be made focusable by adding the tabindex="0"
attribute to the switch element.
Disabled switches
A switch implemented using a checkbox or button element can be disabled by adding the disabled
attribute. In that case, the switch
will not be focusable.
Switches implemented using non-semantic elements can be disabled by adding the aria-disabled="true"
attribute to the switch element.
In that case the developer may choose to make the switch focusable or not. The aria-disabled
attribute should not be used
on a semantic HTML checkbox or button element.
1<!-- Disabled non-semantic HTML switch -->2<div role="switch" aria-label="Dark mode" aria-checked="false" aria-disabled="true">3 ...4</div>56<!-- Disabled non-semantic HTML switch that is focusable -->7<div role="switch" tabindex="0" aria-label="Dark mode" aria-checked="false" aria-disabled="true">8 ...9</div>1011<!-- Switches implemted using semantic elements should not use aria-disabled -->12✓ <button role="switch" aria-checked="false" disabled>...</button>13✓ <input type="checkbox" role="switch" class="on" disabled />14✗ <button role="switch" aria-checked="false" aria-disabled="true">...</button>15✗ <input type="checkbox" role="switch" class="on" aria-disabled="true" />
ARIA owns
If the switch should contain elements that cannot be implemented as descendants of the switch,
the aria-owns
attribute can be used to indicate that the switch owns the elements.
However, since the aria-owns
attribute is not supported by some assistive technologies,
it is best practice to avoid it. If it must be used, the aria-owns
attribute should be set
on the switch and should point to the IDs of the owned elements.
Forbidden interactive children
A switch must not contain any interactive children such as links or buttons. Such children would be inaccessible to screen reader users since they will be excluded from the accessibility tree.
Toggle activation
Conveying the state of the switch
When a switch is activated, its state changes from On to Off or vice versa. The state of the switch must be conveyed to screen reader users.
This can be done by updating the aria-checked
attribute to reflect the new state of the switch.
The aria-checked
attribute must be set to either true
or false
.
1<!-- Switch is initially Off -->2<div3 id="dark-mode-switch"4 role="switch"5 tabindex="0"6 aria-label="Dark mode"7 aria-checked="false"8 class="off"9/>
1function toggleSwitch(switchElement) {2 const isDisabled = switchElement.getAttribute('aria-disabled') === 'true';3 if (isDisabled) {4 // Do nothing if switch is disabled5 return;6 }7 const currentState = switchElement.getAttribute('aria-checked');8 if currentState == 'false' {9 switchElement.classList.add('on');10 switchElement.classList.remove('off');11 switchElement.setAttribute('aria-checked', 'true');12 } else {13 switchElement.classList.add('off');14 switchElement.classList.remove('on');15 switchElement.setAttribute('aria-checked', 'false');16 }17}
Keyboard activation
A switch must be able to be activated using the keyboard. This is important for keyboard users who need to be able to toggle the switch.
This can be achieved by adding a keyup
event listener to the switch element. The event listener should check for the Enter
and Space
keys.
1const switchElement = document.getElementById('dark-mode-switch');2switchElement.addEventListener('click', () => toggleSwitch(switchElement));3switchElement.addEventListener('keyup', (event) => {4 if (event.key === 'Enter' || event.key === ' ') {5 toggleSwitch(switchElement);6 }7});
Toggle activation test
The toggle activation test checks that the switch can be activated by both mouse and keyboard.
It also tests that when activated, the aria-checked
attribute is updated to reflect the new
state of the switch. The test uses the aria-checked
attribute to verify that
the state of the switch changes for each activation method.
It runs three times to test activation using the mouse, the Enter
key and the Space
key.
In the case of an HTML checkbox input, the test will fail if the checkbox element includes
the aria-checked
attribute since a native HTML checkbox should only use the checked
attribute. The rest of the toggle activation test is skipped since keyboard activation and
updating the checked
attribute is handled by the browser.
For switches that are not implemented using a native HTML checkbox, the test will check
that for disabled switches (aria-disabled="true"
), their state does not changed when
clicked or activated using the keyboard.