Checkbox
UI pattern
checkbox role, a descriptive name, and a checked state that changes when users click it or press Space, and keyboard users can reach it.A dual-state checkbox toggles between two values, checked and unchecked. A tri-state checkbox adds a third value, partially checked or mixed, and is most often used to represent and control the combined state of a group of related checkboxes.
For accessibility, a checkbox only has to convey its role, its checked state, and the name of the choice it represents to assistive technology. The checkbox role doesn't say how the choice is applied, though it leans toward being an input: it records a value that the application acts on immediately or later.
A checkbox differs from a switch in semantics and in convention. A checkbox is checked, not checked, or mixed, while a switch is on or off. By convention, a checkbox records a choice that takes effect later, often after the user confirms it, while a switch takes effect immediately. Neither convention is an accessibility requirement.
A toggle button can be mixed, like a checkbox, but its button role says it takes an action rather than recording a choice.
Choose the control whose meaning fits the interface. In a group of options headed "Which of these must be in your pre-takeoff checks?", a checkbox reads better than a switch. For a control that turns the lights on or off, "Lights, switch, on" is easier to understand than "Lights, checkbox, checked".
Build a checkbox with the native HTML <input type="checkbox"> element whenever you can. Browsers give it the checkbox role, a checked state, keyboard operation, and form submission at no cost.
When a design constraint rules out the native input, a non-semantic element can serve as a checkbox by carrying role="checkbox" and an aria-checked state. Keyboard operation and every state change then become your responsibility.
When to Use
Use a checkbox when:
- You're asking the user to mark one or more independent choices.
- The choice is recorded as a value, typically one applied when the user submits a form.
- You need a tri-state checkbox to represent and control the combined state of a group of related checkboxes.
Don't use a checkbox when:
- Only one option from a set can be chosen. Use a radio group instead.
- The choice turns a feature or setting on or off, usually taking effect immediately. Use a switch instead.
- The control performs an action or command rather than recording a value. Use a button or a toggle button instead.
Examples
Code in this section is meant to demonstrate techniques rather than requirements and lacks features needed in a production application.
Native HTML Checkbox
The <input type="checkbox"> element exposes the checkbox role and its checked state, joins the tab order, and toggles with a click or the Space key, all without ARIA or code. Wrapping the input in a <label> gives it an accessible name and makes the label text a click target too.
As a form input, it submits its value under its name when checked. This one sets no value, so it takes the default, and checking it submits security=on.
Native checkbox HTML
<label>
<input type="checkbox" name="security" />
Enhanced security
</label>Custom ARIA Checkbox
The checkbox role tells assistive technology what the element is, aria-checked reports its state, and tabindex="0" puts it in the tab order. Script has to do the rest: toggle aria-checked on a click and on the Space key, through one function, and ignore activation while the checkbox is disabled. CSS draws the box and its checkmark from the aria-checked value, so the appearance can't drift from the reported state.
This example covers only how the checkbox is exposed and operated, not its function as an input. A custom checkbox isn't part of a form, so nothing submits its state. To submit its value with a form, make it a form-associated custom element and set its value with ElementInternals.setFormValue().
Custom checkbox HTML
<span id="security-label">Enhanced security</span>
<span
class="checkbox"
role="checkbox"
tabindex="0"
aria-checked="false"
aria-labelledby="security-label"
></span>Custom checkbox JavaScript
document.querySelectorAll('[role="checkbox"]').forEach((checkbox) => {
const toggle = () => {
if (checkbox.getAttribute("aria-disabled") === "true") return;
const checked = checkbox.getAttribute("aria-checked") === "true";
checkbox.setAttribute("aria-checked", String(!checked));
};
checkbox.addEventListener("click", toggle);
// Prevent Space from scrolling the page, then toggle on release, as a native checkbox does
checkbox.addEventListener("keydown", (event) => {
if (event.key === " ") event.preventDefault();
});
checkbox.addEventListener("keyup", (event) => {
if (event.key === " ") toggle();
});
});Tri-State (Mixed) Checkbox
The tri-state checkbox is a custom checkbox that sets aria-checked="mixed" when only some options in the group are checked, and aria-controls identifies the checkboxes it affects. It needs the same click and Space key handling as the Custom ARIA Checkbox, calling toggleMixedCheckbox(). Each option in the group also needs a change listener that calls updateMixedCheckbox(), so the combined state stays current whichever checkbox the user operates.
Tri-state checkbox HTML
<fieldset>
<legend>Security options</legend>
<div
role="checkbox"
tabindex="0"
aria-checked="mixed"
aria-controls="mfa password-policy password-change"
>
Enhanced security
</div>
<ul>
<li>
<label>
<input type="checkbox" id="mfa" checked />
Multi-factor authentication
</label>
</li>
<li>
<label>
<input type="checkbox" id="password-policy" />
Enforce password policy
</label>
</li>
<li>
<label>
<input type="checkbox" id="password-change" />
Require password change
</label>
</li>
</ul>
</fieldset>Tri-state checkbox JavaScript
function groupOf(mixedCheckbox) {
return mixedCheckbox
.getAttribute("aria-controls")
.split(" ")
.map((id) => document.getElementById(id));
}
// Reflect the group's combined state on the tri-state checkbox
function updateMixedCheckbox(mixedCheckbox) {
const group = groupOf(mixedCheckbox);
const checkedCount = group.filter((checkbox) => checkbox.checked).length;
let state = "mixed";
if (checkedCount === 0) state = "false";
if (checkedCount === group.length) state = "true";
mixedCheckbox.setAttribute("aria-checked", state);
}
// Activating the tri-state checkbox checks every option, or unchecks every option when all are checked
function toggleMixedCheckbox(mixedCheckbox) {
const checkAll = mixedCheckbox.getAttribute("aria-checked") !== "true";
groupOf(mixedCheckbox).forEach((checkbox) => {
checkbox.checked = checkAll;
});
updateMixedCheckbox(mixedCheckbox);
}Structure and Semantics
Assistive technology conveys a checkbox's role, accessible name, and checked state to users. The element that users focus and control should have all three properties.
A native <input type="checkbox"> conveys all of these through HTML. Its checked property reports checked or unchecked, and setting its indeterminate property in code reports the mixed state. The indeterminate property has no HTML attribute and only changes how the checkbox is presented. Activating the checkbox clears indeterminate, and the form submits the checked value whatever the checkbox shows. Don't add aria-checked to a native checkbox, which already manages its state.
A custom checkbox built from a non-semantic element needs ARIA and code for each of these:
| Attribute | How to use |
|---|---|
role | Set to "checkbox" on a custom checkbox. A native <input type="checkbox"> has this role implicitly. |
aria-checked | Set to "true", "false", or "mixed", and update it every time the checkbox toggles. Not used on a native checkbox, which uses checked and indeterminate. |
tabindex | Set to "0" so a custom checkbox joins the tab order. A native checkbox is focusable by default. |
aria-disabled | Set to "true" to disable a custom checkbox. A native checkbox uses the disabled attribute instead. |
The checkbox role makes its content presentational, so assistive technology exposes the text inside a custom checkbox only as part of its accessible name, and any structure or controls inside it are lost.
When a set of checkboxes shares a visible label, group them in a <fieldset> with a <legend>, or in an element with role="group" and aria-labelledby pointing to the label.
Role
A checkbox exposes the checkbox role on the element users focus and operate. An <input type="checkbox"> carries that role implicitly, so a native checkbox needs no role attribute. A custom checkbox declares role="checkbox" on the same element that holds the accessible name, the tab stop, the aria-checked state, and the activation handling.
Has the correct role
Reported as: Element has incorrect role
A checkbox must expose the checkbox role so assistive technology can convey that it's an option users can check.
When a styled <div> or <span> behaves like a checkbox without the role, or carries the wrong one, assistive technology exposes it as plain content or as a different kind of control. Assistive technology users can't tell that it records a choice or whether it's checked.
Use a native <input type="checkbox">, or add role="checkbox" to a custom checkbox.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Applies role to the correct element
Reported as: Incorrect root element
Sanity check. Evinced checks that the checkbox role sits on the element users focus and operate, rather than on a wrapper around it or a descendant inside it. This check runs on every UI pattern, not only on checkboxes.
A checkbox should carry the checkbox role on the element users focus and operate, not on a wrapper around it or a descendant inside it.
When the role sits on one element while the tab stop and the click handling sit on another, assistive technology describes the focused element, which has no role. Users land on the checkbox and aren't told what it is, even though role="checkbox" is in the markup.
Put the role, the accessible name, aria-checked, the tab stop, and the activation handling on one element, and keep any layout wrapper free of roles and handlers.
Accessible Name
The checkbox should have an accessible name that describes the option it represents, not whether it's checked, which its checked state already reports. A name such as "Enhanced security" stays the same whether the checkbox is checked or not.
A native checkbox takes its name from an associated <label>, either wrapping it as in the Native HTML Checkbox example or pointing to its id with the for attribute. A custom checkbox takes its name from its own text content, an aria-label, or an aria-labelledby reference to visible text. The following example shows the methods the earlier examples don't use.
<!-- Native: the label's for attribute points to the checkbox's id -->
<label for="enhanced-security">Enhanced security</label>
<input type="checkbox" id="enhanced-security" />
<!-- Custom: the name comes from the checkbox's text content -->
<div
role="checkbox"
tabindex="0"
aria-checked="false"
>
Enhanced security
</div>
<!-- Custom: the name comes from aria-label -->
<div
role="checkbox"
tabindex="0"
aria-checked="false"
aria-label="Enhanced security"
></div>Has an accessible name
Reported as: Accessible name
A checkbox must have an accessible name that says which option it represents.
When a checkbox has no accessible name, assistive technology can report only its role and state, so screen reader users hear "checkbox, not checked" with no way to know what they would be agreeing to. Voice control users have no name to speak to operate it.
Associate a visible <label> with a native checkbox. For a custom checkbox, give it text content or point aria-labelledby to visible text, and use aria-label only when there's no visible text to reference.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
aria-checked
A custom checkbox reports its state with aria-checked, a state the checkbox role requires. A dual-state checkbox uses true and false, and a tri-state checkbox also uses mixed. A native checkbox reports the same states through its checked and indeterminate properties, so it needs no aria-checked.
Declares its current state
Reported as: No toggle indicator
A custom checkbox must declare its current state with aria-checked.
When the checkmark is drawn from a CSS class and aria-checked is missing, the checkbox looks complete but declares no state, so it can be reported as not checked whatever it shows. Screen reader users can't tell the current setting before they act, or whether their action took effect.
Set aria-checked to true, false, or mixed when the checkbox first renders, not on the first interaction, and keep it in step with what's on screen. Better still, use a native <input type="checkbox">, which reports its state without any attribute of yours.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Uses a defined state value
Reported as: Invalid toggle attribute value
A checkbox's aria-checked attribute must be set to the string true, false, or mixed.
When aria-checked carries any other value, such as checked, on, 1, or an empty string, browsers and assistive technology ignore it or assume a default of their own, and screen reader users can hear a state that doesn't match what the checkbox shows. The checkbox otherwise looks and behaves normally, so the mismatch is easy to miss.
Convert the application's internal state to true, false, or mixed in one place, where the attribute is written, rather than passing internal values straight through to the DOM.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Color Alone State Indication
A checkbox shows its state with a mark, not with color alone. A native checkbox draws a checkmark when checked and a dash when mixed. A restyled or custom checkbox needs a mark of its own, drawn from its checked or aria-checked state so the mark and the reported state change together.
Shows state by more than color
Reported as: State indicated by color alone
A checkbox must show its checked, unchecked, and mixed states with a visual change other than color.
When the only difference between states is a fill color, such as a box that turns from white to the brand color, people with color vision deficiency or low vision, or using a high-contrast display, can't tell whether the option is checked. Exposing the state to assistive technology doesn't help, because most of these users don't use any.
Draw a checkmark in the checked state and a dash in the mixed state, and keep any color change alongside them. Whatever tells the states apart needs a contrast of at least 3:1 with the colors around it. Draw the mark with an SVG, a border, or text rather than a CSS background color, which high-contrast modes can remove.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.4.1 Use of Color (A) | Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element. |
Disabled
A disabled checkbox reports its disabled state with the attribute that suits how it's built. A native checkbox uses the disabled attribute, which also removes it from the tab order and blocks activation. A custom checkbox uses aria-disabled="true", which only reports the state, so code has to block activation and manage the tab stop.
The following example shows the correct attribute for each kind of checkbox.
<!-- Native: use the disabled attribute -->
<input type="checkbox" id="mfa" disabled />
<!-- Not this: aria-disabled on a native checkbox -->
<input type="checkbox" id="mfa" aria-disabled="true" />
<!-- Custom: use aria-disabled, and take it out of the tab order -->
<div
role="checkbox"
tabindex="-1"
aria-checked="false"
aria-disabled="true"
>
Enhanced security
</div>Avoids conflicting disabled states
Reported as: Conflicting disabled values
A checkbox must have a single, consistent disabled state.
When a checkbox sets its disabled state two ways and the values disagree, such as the disabled attribute alongside aria-disabled="false", assistive technology may report a state the browser doesn't enforce. Users can't tell whether they're able to change the option.
Set the disabled state once: the disabled attribute on a native checkbox, or aria-disabled on a custom one, never both.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Uses aria-disabled rather than disabled
Reported as: Element does not support the disabled attribute
A custom checkbox must convey its disabled state with aria-disabled, not the disabled attribute.
When disabled is set on the <div> or <span> behind a custom checkbox, the browser ignores it. The checkbox stays in the accessibility tree as an ordinary, available checkbox, so users are told they can change an option the design means to be unavailable, even when styling grays it out.
Set aria-disabled="true" instead, and block activation in code while it's set. When a native <input type="checkbox"> would do the job, switch to it, and its disabled attribute handles the state, the tab order, and activation.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Disables only elements that support it
Reported as: Element type does not support disabled state
An element in a checkbox must carry disabled or aria-disabled only when its role supports a disabled state.
When the state sits on an element whose role has none, such as a wrapper, a list item or a heading, assistive technology may drop it or report it on something users can't operate, while the control that really is unavailable is still reported as available.
Remove the attribute from that element, and set the disabled state on the control itself, using an element or role that supports it, such as a native <button>.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Forbidden Interactive Children
A checkbox contains no other interactive elements. The checkbox role makes everything inside it presentational, so a link or button placed inside a checkbox loses its role and its name and drops out of the accessibility tree, even though it's visible on screen.
Avoids nested interactives
Reported as: Forbidden interactive children; Nested interactive elements
A checkbox must not contain another interactive element, such as a link or a button.
When a control is nested inside a checkbox, assistive technology users get one control where sighted users see two, and the inner one can't be reached or operated. A click or a key press also has two plausible targets, so it's unclear whether it toggles the checkbox or activates the inner control.
Move the inner control out of the checkbox and make the two siblings, each with its own role, accessible name, and activation behavior. A link to terms and conditions, for example, belongs next to the checkbox's label, not inside the checkbox.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Relationships
A checkbox is a single element that owns nothing. Its content is presentational and contributes only to its accessible name. A tri-state checkbox represents the state of a group of other checkboxes, but it doesn't contain them. Set aria-controls on it to the ids of the checkboxes it affects, and update each one's state directly in code, as the Tri-State (Mixed) Checkbox example shows.
aria-owns
A checkbox is a single control, not a container. Its children are presentational, so its label and the options a tri-state checkbox represents sit outside it and relate to it by reference.
Avoids aria-owns
Reported as: Avoid aria-owns
General check. Evinced checks that the checkbox doesn't use aria-owns to claim elements elsewhere in the document as its children. This check runs on every UI pattern, not only on checkboxes.
A checkbox should not own other elements with aria-owns.
When a checkbox owns its label or the checkboxes in a tri-state group, those elements become its children, so they're presentational too. Depending on the browser and assistive technology, the owned content can drop out of browse mode or be folded into the checkbox's name, and screen reader users may hear it inconsistently or twice. When it's focusable, focus can land on something with no role or name.
Remove aria-owns from the checkbox and keep the content outside it. Reference the label with aria-labelledby, and the checkboxes a tri-state checkbox affects with aria-controls.
Operation
With a pointer, clicking a checkbox toggles it, and clicking the label of a native checkbox does the same. With a keyboard, the Tab key moves focus to the checkbox and pressing Space toggles it. Enter doesn't toggle a checkbox. In a form, Enter may submit the form instead.
Each activation changes the checked state: a native checkbox updates its checked property, and a custom checkbox toggles aria-checked between true and false. A disabled checkbox doesn't change state from either input method.
A native <input type="checkbox"> provides all of this. A custom checkbox has to reproduce it in code, with click, keydown, and keyup listeners that run the same toggle code, as the Custom ARIA Checkbox example shows.
Focus Sequence
An enabled checkbox is in the tab order. A native <input type="checkbox"> is focusable on its own, and a custom checkbox needs tabindex="0". Either way, the tab stop belongs on the same element that carries the checkbox role and the accessible name, so that what users land on is what assistive technology describes.
Reachable by keyboard
Reported as: Keyboard accessible
A checkbox must be reachable with the Tab key.
When a custom checkbox is built from a <div> or <span> with a role and click handling but no tabindex, keyboard users can't reach it, so they can't check or uncheck the option.
Use a native <input type="checkbox">, which is focusable on its own, or add tabindex="0" to a custom checkbox so it joins the tab order in document order.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Skips tab order when disabled
Reported as: Disabled element focusable
A checkbox that presents as disabled shouldn't be in the tab order.
When a disabled checkbox keeps its tab stop, keyboard users land on an option they can't change. In a form with several disabled checkboxes, keyboard users pass through a stop for each one.
Use the disabled attribute on a native checkbox, which removes it from the tab order. On a custom checkbox, set tabindex="-1" while aria-disabled="true" is set, and restore tabindex="0" when it becomes available.
Keeping a disabled checkbox focusable is a recognized alternative, since users can then find it and learn why it's unavailable. If you take that route, make sure the disabled state is exposed and activation is blocked.
Severity: Minor
Element that carries role receives focus
Reported as: Focusable offset
A checkbox must receive focus on the element that carries the checkbox role, not on one of its descendants.
When focus lands on a child of the element with role="checkbox", assistive technology describes that child, which has no role or state. Users tabbing through the page aren't told they've reached a checkbox or whether it's checked.
Make the element with the role focusable with tabindex="0", or use a native <input type="checkbox">, and remove focusability from the descendant that was taking focus instead.
Severity: Minor
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 2.1.1 Keyboard (A) | All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints. |
| EN 301 549 | 9.2.1.1 Keyboard | Same as the WCAG text. |
| Section 508 | 1194.21(a) | When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually. |
| 508 Trusted Tester | 2.1.1-keyboard-access, 4.A | All functionality can be accessed and executed using only the keyboard. |
Context Change
A checkbox's choice can take effect as soon as it's checked or wait for the user to submit a form, and either is fine while the effect stays in place. Submitting the form, loading another page, or moving focus does change the context. Start it from an explicit control such as a submit button, or warn about it in text before the checkbox.
Keeps context when a value changes
Reported as: Unexpected context change on input
Changing a checkbox's state must not change the context unless users are told beforehand that it will.
When checking a box submits the form, reloads the page, opens a dialog, or moves focus, as a filter that applies on every check often does, screen reader and screen magnifier users may not notice that the page changed. Keyboard users lose their place, and a form that submits partway through can discard what the user hadn't finished entering.
Update the page in place and leave focus on the checkbox. Start submission or navigation from an explicit control such as an Apply button, or, when the change of context is intended, say so in text that comes before the checkbox.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 3.2.2 On Input (A) | Changing the setting of any user interface component does not automatically cause a change of context unless the user has been advised of the behavior before using the component. |
| EN 301 549 | 9.3.2.2 On Input | Same as the WCAG text. |
| Section 508 | 1194.22(n) | When electronic forms are designed to be completed on-line, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. |
| Section 508 | 1194.21(l) | When electronic forms are used, the form shall allow people using assistive technology to access the information, field elements, and functionality required for completion and submission of the form, including all directions and cues. |
Toggle Activation
A checkbox toggles its checked state each time the user clicks it or presses Space while it has focus, and the state it reports changes with it. A native checkbox manages this through its checked property. A custom checkbox updates aria-checked in the same code that changes how it looks, so the reported state and the visible state can't drift apart.
Updates the state on activation
Reported as: Element's state did not change
Activating a custom checkbox, with a pointer or the keyboard, must update aria-checked to its new state.
When the checkmark changes but aria-checked keeps its starting value, sighted users see the checkbox toggle while assistive technology reports the old state. A screen reader user who checks the box hears no change and, returning to it later, is told it's still unchecked.
Derive aria-checked and the checkbox's appearance from the same state, and write both in one place. Handle the click and the Space key through that one code path.
Evinced reports this issue as Critical or as Serious, depending on the context where it shows up.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Returns to its earlier state
Reported as: Toggle state not resetting
Activating a checkbox twice must return its reported state to where it started.
When a handler sets aria-checked to a fixed value instead of inverting it, the checkbox reports the right state once and then stays there. A user who unchecks the option is told it's still checked, and their attempt to correct it appears to change nothing.
Invert the current state on each activation, reading it from the same place that renders it, rather than assigning a fixed value.
Evinced reports this issue as Critical or as Serious, depending on the context where it shows up.
Severity: Critical
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Leaves native state to HTML
Reported as: Invalid toggle attribute
A native <input type="checkbox"> must not also carry aria-checked.
When a native checkbox has aria-checked alongside its own checked property, the two can disagree. The browser updates checked on every activation, while aria-checked holds whatever value the code last wrote, so a checkbox the user has just checked can be reported as unchecked.
Remove aria-checked from the native checkbox and let checked, and indeterminate for a mixed state, report the state. Keep aria-checked for custom checkboxes, which have no native state to report.
Severity: Serious
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| EN 301 549 | 9.4.1.2 Name, Role, Value | Same as the WCAG text. |
| Section 508 | 1194.21(d) | Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text. |
Ignores activation when disabled
Reported as: Disabled element active
A checkbox that presents as disabled must not change state when it's activated.
When a custom checkbox carries aria-disabled="true" but keeps its click and key handlers, activating it still toggles aria-checked. Screen reader users hear the checkbox announced as unavailable and then hear its state change, so they can't trust either signal or tell whether the change took effect.
Check the disabled state at the start of the toggle handler and return before changing anything, covering the pointer and keyboard paths. For a native checkbox, the disabled attribute blocks activation with no code.
Severity: Moderate
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 9.1.3.1 Info and Relationships | Same as the WCAG text. |
Event Listener Type
When script in a checkbox responds to keys, it listens for keydown or keyup. The keypress event is deprecated, and browsers don't fire it for many keys, including the arrow keys, Home, End and Escape.
Avoids the keypress event
Reported as: Deprecated keypress listener
A checkbox's key handling should use keydown or keyup, not keypress.
When a handler listens for keypress, keys the browser doesn't send through that event go unanswered, and keyboard users find the checkbox ignoring keys it's meant to respond to.
Replace each keypress listener with a keydown listener, and read the key from event.key.
Severity: Minor
FAQ
Which WCAG success criteria do the checkbox issues relate to?
Most relate to 4.1.2 Name, Role, Value: the checkbox's role, its accessible name, its checked state and the values it takes, how it conveys a disabled state, updating and reversing that state on activation, and keeping other interactive elements out of it.
Reaching the checkbox with the Tab key and putting focus on the element with the role relate to 2.1.1 Keyboard. Showing the state by more than color relates to 1.4.1 Use of Color, keeping the context when the state changes to 3.2.2 On Input, and a disabled checkbox that still changes state to 1.3.1 Info and Relationships.
Taking a disabled checkbox out of the tab order maps to no WCAG success criterion and is a best practice.
Why are some checkbox issues marked as Critical and others as Minor?
Severity reflects how much an issue gets in users' way. Critical issues stop users outright: a checkbox with no role, name, or reported state, one keyboard users can't reach, or one whose reported state doesn't follow activation. Serious issues confuse users though tasks are still possible, such as showing the state by color alone, reporting a disabled or checked state the checkbox doesn't have, nesting controls, or changing the context without warning. An invalid aria-checked value, or a disabled checkbox that still toggles, is Moderate. A disabled checkbox left in the tab order, or focus that lands inside the checkbox rather than on it, is Minor.
The aria-owns check and the check on where the role sits carry no severity: Evinced reports them as a general check and a sanity check.
Related Patterns
- Switch: turns a feature or setting on or off, usually taking effect immediately
- Toggle Button: a button that can be pressed or not, which takes an action rather than recording a choice
- Radio Group: a set of options from which only one can be chosen
- Button: performs an action or command rather than recording a value