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 security
4 <input type="checkbox" />
5</label>
6
7<!-- The `label[for]` attribute may also be used instead of
8 wrapping the input in a label tag -->
9<label for="enhanced-security">
10 Enhanced security
11</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</div
3
4<!-- Checkbox gets its accessible name from the aria-label attribute -->
5<div role="checkbox" tabindex="0" aria-label="Enhanced security" aria-checked="false"></div>
6
7<!-- Checkbox gets its accessible name from the aria-labelledby attribute -->
8<span id="enhanced-security-label">Enhanced security</span>
9<div
10 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<div
3 role="checkbox"
4 aria-label="Enhanced security"
5 aria-checked="false"
6 aria-disabled="true"
7></div>
8
9<!-- Disabled non-semantic HTML checkbox that is focusable -->
10<div
11 role="checkbox"
12 tabindex="0"
13 aria-label="Enhanced security"
14 aria-checked="false"
15 aria-disabled="true"
16></div>
17
18<!-- 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<div
3 role="checkbox"
4 tabindex="0"
5 aria-checked="false"
6 aria-controls="mfa password-policy password-change"
7 data-mixed-checkbox
8>
9 Enhanced security
10</div>
11<ul class="checkboxes">
12 <li>
13 <label>
14 <input type="checkbox" id="mfa" />
15 Multi-factor authentication
16 </label>
17 </li>
18 <li>
19 <label>
20 <input type="checkbox" id="password-policy" />
21 Enforce password policy
22 </label>
23 </li>
24 <li>
25 <label>
26 <input type="checkbox" id="password-change" />
27 Require password change
28 </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.

Summary of Tests

NameConformance LevelWCAG Success Criteria
RoleA4.1.2 Name, Role, Value
Accessible nameA4.1.2 Name, Role, Value
Focus sequenceA2.1.1 Keyboard, 2.4.3 Focus Order
ARIA checkedA1.3.1 Info and Relationships
ARIA ownsA1.3.1 Info and Relationships
Forbidden interactive childrenA4.1.2 Name, Role, Value
Toggle activationA2.1.1 Keyboard, 4.1.2 Name, Role, Value