Checkbox
A checkbox is an input widget that supports up to three states. Dual-state checkboxes toggle between two states: checked and unchecked. Tri-state checkboxes toggle between three states: checked, unchecked and partially checked. A common use case for tri-state checkboxes is to toggle the selection of a group of items. Checkboxes are similar to switches and toggle buttons, which can also serve as binary inputs. Checkboxes are most commonly used in forms where the user is asked to select one or more options from a list of options and changes to the checkbox state are applied followign a form submission.
A dual-state checkbox may be implemented using a semantic HTML checkbox (recommended), or a
non-semantic element with role="checkbox"
. A tri-state checkbox must be implemented using a
non-semantic element with role="checkbox"
.
Role
A checkbox widget must have a role of switch. If a checkbox is implemented using a semantic HTML checkbox,
the role is provided by the browser. If a checkbox is implemented using a non-semantic element, the role
must be provided using the role="checkbox"
attribute.
Accessible name
A checkbox 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 checkbox. If an HTML checkbox input is used, the accessible name should be provided by the checkbox label. The accessible name should convey the functionality of the checkbox but not the current state of the checkbox.
1<!-- The checkbox label constitutes the accessible name -->2<label>3 Enhanced security4 <input type="checkbox" />5</label>67<!-- The `label[for]` attribute may also be used instead of8 wrapping the input in a label tag -->9<label for="enhanced-security">10 Enhanced security11</label>12<input type="checkbox" id="enhanced-security" />
If the checkbox is implemented using a non-semantic element, it is possible to provide the accessible name
from contained content nodes or using the aria-label
or aria-labelledby
attributes.
1<!-- Checkbox gets its accessible name from contained text node -->2<div role="checkbox" tabindex="0" aria-checked="false">Enhanced security</div34<!-- Checkbox gets its accessible name from the aria-label attribute -->5<div role="checkbox" tabindex="0" aria-label="Enhanced security" aria-checked="false"></div>67<!-- Checkbox gets its accessible name from the aria-labelledby attribute -->8<span id="enhanced-security-label">Enhanced security</span>9<div10 role="checkbox"11 tabindex="0"12 aria-labelledby="enhanced-security-label"13 aria-checked="false"14></div>
Focus sequence
A checkbox must be focusable unless it is disabled. This is important for keyboard users who need to be able to navigate the checkbox.
Semantic HTML inputs are always focusable when not disabled. Checkboxes implemented using non-semantic elements
can be made focusable by adding the tabindex="0"
attribute to the checkbox element.
Disabled checkboxes
A checkbox implemented using a HTML checkbox input can be disabled by adding the disabled
attribute.
In that case, the checkbox will not be focusable.
Checkboxes implemented using non-semantic elements can be disabled by adding the aria-disabled="true"
attribute to the checkbox element. In that case the developer may choose to make the checkbox focusable or not.
The aria-disabled
attribute should not be used on a semantic HTML checkbox.
1<!-- Disabled non-semantic HTML checkbox -->2<div3 role="checkbox"4 aria-label="Enhanced security"5 aria-checked="false"6 aria-disabled="true"7></div>89<!-- Disabled non-semantic HTML checkbox that is focusable -->10<div11 role="checkbox"12 tabindex="0"13 aria-label="Enhanced security"14 aria-checked="false"15 aria-disabled="true"16></div>1718<!-- Checkboxes implemted using semantic elements should not use aria-disabled -->19✓ <input type="checkbox" disabled />20✗ <input type="checkbox" aria-disabled="true" />
ARIA owns
If the checkbox should contain elements that cannot be implemented as descendants of the checkbox,
the aria-owns
attribute can be used to indicate that the checkbox 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 checkbox and should point to the IDs of the owned elements.
Forbidden interactive children
A checkbox 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 checkbox
When a checkbox is activated, its state changes from checked to unchecked or vice versa.
In a tri-state checkbox, the state may also change from or to partially checked.
The state of the checkbox must be conveyed to screen reader users.
This can be done by updating the aria-checked
attribute to reflect the new state of the checkbox.
The aria-checked
attribute must be set to either true
or false
.
For tri-state checkboxes, the aria-checked
attribute may also be set to mixed
to indicate that
the checkbox is partially checked.
1<!-- Tri-state checkbox example -->2<div3 role="checkbox"4 tabindex="0"5 aria-checked="false"6 aria-controls="mfa password-policy password-change"7 data-mixed-checkbox8>9 Enhanced security10</div>11<ul class="checkboxes">12 <li>13 <label>14 <input type="checkbox" id="mfa" />15 Multi-factor authentication16 </label>17 </li>18 <li>19 <label>20 <input type="checkbox" id="password-policy" />21 Enforce password policy22 </label>23 </li>24 <li>25 <label>26 <input type="checkbox" id="password-change" />27 Require password change28 </label>29 </li>30</ul>
1function updateMixedCheckbox(mixedCheckbox) {2 const ariaControls = mixedCheckbox.getAttribute('aria-controls');3 const controlledCheckboxes = ariaControls.split(' ');4 const checkedCheckboxes = controlledCheckboxes.filter((id) => {5 const checkbox = document.getElementById(id);6 return checkbox.checked;7 });8 const isMixed = checkedCheckboxes.length > 0 && checkedCheckboxes.length < controlledCheckboxes.length;9 if (isMixed) {10 mixedCheckbox.setAttribute('aria-checked', 'mixed');11 } else {12 mixedCheckbox.setAttribute('aria-checked', checkedCheckboxes.length > 0);13 }14}15function toggleMixedCheckbox(event) {16 const checkbox = event.target;17 const ariaControls = checkbox.getAttribute('aria-controls');18 const currentState = checkbox.getAttribute('aria-checked');19 const controlledCheckboxes = ariaControls.split(' ');20 controlledCheckboxes.forEach((id) => {21 const controlledCheckbox = document.getElementById(id);22 controlledCheckbox.checked = currentState === 'mixed' || currentState === 'false';23 });24 updateMixedCheckbox(checkbox);25}
Keyboard activation
A checkbox must be able to be activated using the keyboard.
This is important for keyboard users who need to be able to toggle the checkbox.
Native HTML checkboxes can automatically be activated using the Space
key.
For non-semantic checkboxes the developer must add a keyup
event listener to the checkbox element.
The event listener should check for the Space
key.
1const mixedCheckboxes = document.querySelectorAll('[data-mixed-checkbox]');2mixedCheckboxes.forEach((mixedCheckbox) => {3 mixedCheckbox.addEventListener('click', toggleMixedCheckbox);4 mixedCheckbox.addEventListener('keyup', (event) => {5 if (event.key === ' ') {6 toggleMixedCheckbox(event);7 }8 });9 const ariaControls = mixedCheckbox.getAttribute('aria-controls');10 const controlledCheckboxes = ariaControls.split(' ');11 controlledCheckboxes.forEach((id) => {12 const controlledCheckbox = document.getElementById(id);13 controlledCheckbox.addEventListener('change', () => updateMixedCheckbox(mixedCheckbox));14 });15});
Toggle activation test
The toggle activation test checks that the checkbox 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 checkbox. The test uses the aria-checked
attribute to verify that
the state of the checkbox changes for each activation method.
It runs twice times to test activation using the mouse 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 checkboxes 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.