Switch
UI pattern
switch role, a descriptive name, and an on or off state that changes when users click it or press Space, and keyboard users can reach it.Assistive technology conveys a switch's name, role, and current state, so a screen reader user hears something like "Dark mode, switch, on".
A switch, a checkbox, and a toggle button each expose a state that changes when the user activates them, but they aren't interchangeable. For accessibility, a switch only has to turn something on or off and convey its role, its state, and the name of the setting to assistive technology.
The switch role doesn't say how the setting is applied. A switch can work as an input that records a value for the application to act on immediately or after a later confirmation, or like a button that turns the feature on or off directly.
A switch differs from a checkbox in semantics and in convention. A switch is on or off, while a checkbox is checked, not checked, or mixed. By convention, a switch takes effect immediately, while a checkbox records a choice that takes effect later, often after the user confirms it. 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. For a control that turns the lights on or off, "Lights, switch, on" is easier to understand than "Lights, checkbox, checked". In a group of options headed "Which of these must be in your pre-takeoff checks?", the checkbox reads better.
There are three ways to build a switch. The recommended one is a native <input type="checkbox"> with role="switch", which gets its focus, keyboard operation, state, and form submission from the browser. A <button> with role="switch" gets focus and keyboard operation from the browser, while code manages its state. A non-semantic element with role="switch" needs code for everything.
When to Use
Use a switch when:
- The user turns a single setting, feature, or device on or off.
- The change takes effect immediately, without submitting a form.
- On and off describe the choice better than checked and unchecked.
Don't use a switch when:
- The choice needs a partial or mixed state. Use a checkbox instead.
- The choice is recorded when a form is submitted. Use a checkbox instead.
- Only one option from a set can be chosen. Use a radio group instead.
- The control performs an action or command rather than setting 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.
Each example builds a switch that turns dark mode on and off.
Native HTML Checkbox Switch
A native checkbox becomes a switch when it carries role="switch". The browser still supplies the rest: the input joins the tab order, toggles with a click or the Space key, reports its state through the checked property, and submits its value with a form. Wrapping the input in a <label> gives the switch its accessible name and makes the label text a click target too.
CSS can restyle the input as a switch without changing any of this.
Native switch HTML
<label>
Dark mode
<input
type="checkbox"
role="switch"
name="dark-mode" />
</label>Switch Using an HTML Button
A <button> with role="switch" gets its tab stop and its keyboard operation from the browser: pressing Enter or Space fires a click event, so one click handler covers pointer and keyboard. The handler inverts aria-checked, and CSS shows the On or Off text from that value, so the appearance can't drift from the reported state.
The button's text content supplies its accessible name. The On and Off text carries aria-hidden="true", which keeps the state out of the name and leaves aria-checked to report it. The type="button" attribute stops the switch from submitting a form it sits in.
Button switch HTML
<button
type="button"
class="switch"
role="switch"
aria-checked="false">
<span class="label">Dark mode</span>
<span class="on" aria-hidden="true">On</span>
<span class="off" aria-hidden="true">Off</span>
</button>Button switch CSS
.switch[aria-checked="true"] .off,
.switch[aria-checked="false"] .on {
display: none;
}Button switch JavaScript
document.querySelectorAll('button[role="switch"]').forEach((button) => {
button.addEventListener("click", () => {
const on = button.getAttribute("aria-checked") === "true";
button.setAttribute("aria-checked", String(!on));
});
});Custom ARIA Switch
A switch built from a <div> gets nothing from the browser. The switch role tells assistive technology what the element is, aria-checked reports its state, tabindex="0" puts it in the tab order, and aria-labelledby names it from the visible text beside it.
Custom switch HTML
<span id="dark-mode-label">Dark mode</span>
<div
class="switch"
role="switch"
tabindex="0"
aria-checked="false"
aria-labelledby="dark-mode-label">
<span class="on" aria-hidden="true">On</span>
<span class="off" aria-hidden="true">Off</span>
</div>Script does the rest. One function toggles aria-checked and ignores activation while the switch is disabled, and the click, Enter, and Space handlers all call it. Enter toggles on key press and Space on key release, as they do on a native button.
Custom switch JavaScript
function toggleSwitch(switchElement) {
if (switchElement.getAttribute("aria-disabled") === "true") return;
const on = switchElement.getAttribute("aria-checked") === "true";
switchElement.setAttribute("aria-checked", String(!on));
}
document.querySelectorAll('div[role="switch"]').forEach((switchElement) => {
switchElement.addEventListener("click", () => toggleSwitch(switchElement));
switchElement.addEventListener("keydown", (event) => {
// Stop Space from scrolling the page
if (event.key === " ") event.preventDefault();
if (event.key === "Enter") toggleSwitch(switchElement);
});
switchElement.addEventListener("keyup", (event) => {
if (event.key === " ") toggleSwitch(switchElement);
});
});This switch doesn't submit its value with a form. To submit it, make the switch a form-associated custom element and set its value with ElementInternals.setFormValue().
Structure and Semantics
Assistive technology conveys the role, accessible name, and checked state of a switch to users. The element that users focus and control should have all three properties.
How each gets there depends on the construction:
- A native
<input type="checkbox">takes theswitchrole fromrole="switch"and keeps reporting its state through itscheckedproperty. Don't addaria-checkedto it. - A
<button>also takes the role fromrole="switch", which replaces itsbuttonrole, and reports its state witharia-checked. - A non-semantic element needs the role,
aria-checked, and a tab stop, all set by you.
| Attribute | How to use |
|---|---|
role | Set to "switch" on every construction, including a native checkbox. |
aria-checked | Set to "true" when the switch is on and "false" when it's off, and update it every time the switch toggles. Not used on a native checkbox, which uses checked. |
tabindex | Set to "0" on a switch built from a non-semantic element. A native checkbox or button is focusable by default. |
aria-disabled | Set to "true" to disable a switch built from a non-semantic element. A native checkbox or button uses the disabled attribute instead. |
aria-describedby | Points to any static text that explains the switch further, such as what turning it on affects. |
The switch role makes its content presentational, so assistive technology exposes the text inside a switch only as part of its accessible name, and any structure or controls inside it are lost. Visible On and Off text inside a switch joins the name unless it's hidden with aria-hidden="true".
When a set of switches 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 switch exposes the switch role on the element users focus and operate, whichever way it's built. A native checkbox is exposed as a checkbox until it carries role="switch", so the role is needed there too. On a <button> or a non-semantic element, the role goes on the same element that holds the accessible name, the tab stop, the state, and the activation handling.
Has the correct role
Reported as: Element has incorrect role
A switch must expose the switch role so assistive technology can convey that it turns a setting on or off.
When a control that works as a switch has no role, or a native checkbox or button keeps its own role, assistive technology exposes it as plain content, a checkbox, or a button. Screen reader users hear the wrong kind of control, or no state, and can't tell that it turns a setting on or off.
Add role="switch" to the native checkbox, button, or other element that users operate.
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 switch 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 switches.
A switch should keep its role, accessible name, state, and tab stop on one element.
When role="switch" sits on a wrapper while the native checkbox or button inside it takes focus, assistive technology describes the focused element, which isn't a switch. Screen reader users land on the control and hear "checkbox" or "button", even though role="switch" is in the markup.
Put role="switch" on the checkbox, button, or element that receives focus, and keep any layout wrapper free of roles and handlers.
Accessible Name
A switch's accessible name says what it turns on or off, such as "Dark mode", and stays the same whichever state the switch is in. The state is reported by checked or aria-checked, so a name that also carries it, such as "Dark mode on", repeats the state or contradicts it after the next toggle. Keep visible On and Off text out of the name with aria-hidden="true".
A native checkbox switch takes its name from an associated <label>, and a switch built from a button or another element takes it from its text content, an aria-labelledby reference, or an aria-label. The following example shows the two methods the builds in Examples don't use.
<!-- Native: the label's for attribute points to the switch's id -->
<label for="dark-mode">Dark mode</label>
<input
type="checkbox"
id="dark-mode"
role="switch" />
<!-- Custom: the name comes from aria-label -->
<div
role="switch"
tabindex="0"
aria-checked="false"
aria-label="Dark mode">
<span class="on" aria-hidden="true">On</span>
<span class="off" aria-hidden="true">Off</span>
</div>Has an accessible name
Reported as: Accessible name
A switch must have an accessible name that says which setting it turns on or off.
When a switch has no accessible name, assistive technology can report only its role and state, so screen reader users hear "switch, off" with no way to know what it controls. Voice control users have no name to speak to operate it.
Associate a visible <label> with a native checkbox switch. For a button or another element, 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 switch built from a button or a non-semantic element reports whether it's on with aria-checked, a state the switch role requires. Only two values declare its state reliably: true for on and false for off. Unlike a checkbox, a switch has no mixed state, and mixed counts as false. A native checkbox switch reports its state through the checked property instead and needs no aria-checked.
Declares its current state
Reported as: No toggle indicator
A switch built from a button or a non-semantic element must declare its current state with aria-checked.
When the thumb's position is drawn from a CSS class and aria-checked is missing, the switch looks complete but declares no state, so it can be reported as off 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 or false when the switch first renders, not on the first interaction, and keep it in step with what's on screen. A native checkbox switch reports its state through checked 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 switch's aria-checked attribute must be set to the string true or false.
When aria-checked carries any other value, such as 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 switch shows. The value mixed is equivalent to false on a switch, so a switch set to mixed is reported as off whatever it shows.
Convert the application's internal state to true or false in one place, where the attribute is written.
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 switch shows whether it's on by the position of its thumb, by visible On and Off text, or both, not by the color of its track alone. A native checkbox restyled as a switch loses its checkmark, so the styling has to supply a cue of its own.
Shows state by more than color
Reported as: State indicated by color alone
A switch must show whether it's on or off with a visual change other than color.
When the only difference between states is the track color, such as gray for off and green for on, people with color vision deficiency or low vision, or using a high-contrast display, can't tell whether the setting is on. Exposing the state to assistive technology doesn't help, because most of these users don't use any.
Move the thumb to the other end of the track or show On and Off text, and keep any color change alongside it. Whatever tells the states apart needs a contrast of at least 3:1 with the colors around it. Draw the thumb and track with an SVG or borders rather than CSS background colors, 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 switch reports its disabled state with the attribute that suits how it's built. A native checkbox or button uses the disabled attribute, which also removes it from the tab order and blocks activation. A switch built from a non-semantic element 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 a switch built from a button.
<!-- Button: use the disabled attribute -->
<button
type="button"
role="switch"
aria-checked="false"
disabled>
Dark mode
</button>
<!-- Not this: aria-disabled on a button -->
<button
type="button"
role="switch"
aria-checked="false"
aria-disabled="true">
Dark mode
</button>Avoids conflicting disabled states
Reported as: Conflicting disabled values
A switch must have a single, consistent disabled state.
When a switch 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 setting.
Set the disabled state once: the disabled attribute on a native checkbox or button switch, or aria-disabled on a switch built from a non-semantic element, 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 switch built from a non-semantic element must convey its disabled state with aria-disabled, not the disabled attribute.
When disabled is set on the <div> or <span> behind a switch, the browser ignores it. The switch stays in the accessibility tree as an ordinary, available switch, so users are told they can change a setting 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 checkbox or a button would do the job, use 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 switch 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 switch contains no other interactive elements. The switch role makes everything inside it presentational, so a link or button placed inside a switch loses its role and its name and drops out of the accessibility tree, even though it's visible on screen. A "Learn more" link belongs next to the switch, not inside it.
Avoids nested interactives
Reported as: Forbidden interactive children; Nested interactive elements
A switch must not contain another interactive element, such as a link or a button.
When a control is nested inside a switch, 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 switch or activates the inner control.
Move the inner control out of the switch and make the two siblings, each with its own role, accessible name, and activation behavior.
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 switch is a single element that owns nothing. Its content is presentational and contributes only to its accessible name.
aria-owns
A switch has no reason to use aria-owns.
Avoids aria-owns
Reported as: Avoid aria-owns
General check. Evinced checks that the switch 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 switches.
A switch should not own other elements with aria-owns.
The switch role allows only presentational children, and browsers and assistive technology handle aria-owns on a switch inconsistently. When a switch owns another element, that element can lose any role it carries, so screen reader users may not be told what it is or that it's there.
Remove aria-owns from the switch, and put only presentational content inside a custom switch. That content can supply the accessible name, or aria-labelledby can reference visible text.
Operation
With a pointer, clicking a switch toggles it, and clicking its associated <label> does the same. With a keyboard, the Tab key moves focus to the switch and pressing Space toggles it. Enter is optional for a switch, and support differs by construction: a native checkbox switch doesn't respond to it, while a button switch does. Make a switch built from a non-semantic element respond to Enter too.
Each activation turns the switch on or off, and the reported state changes with it: a native checkbox updates its checked property, and any other switch toggles aria-checked between true and false. The change usually takes effect immediately. A disabled switch doesn't change state from any input method.
A native checkbox switch provides all of this. A button switch needs only a click handler that updates aria-checked. A switch built from a non-semantic element has to reproduce everything in code, as the Custom ARIA Switch example shows.
Focus Sequence
An enabled switch is in the tab order. A native checkbox or button is focusable on its own, and a switch built from a non-semantic element needs tabindex="0". Either way, the tab stop belongs on the element that carries the switch role and the accessible name.
A disabled native switch leaves the tab order through its disabled attribute. A disabled custom switch can leave it with tabindex="-1" or stay focusable, as long as its disabled state is exposed.
Reachable by keyboard
Reported as: Keyboard accessible
A switch must be reachable with the Tab key.
When a switch 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 turn the setting on or off.
Use a native checkbox or a button, which is focusable on its own, or add tabindex="0" to a switch built from another element 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 switch that presents as disabled shouldn't be in the tab order.
When a disabled switch keeps its tab stop, keyboard users land on a setting they can't change. In a settings panel with several disabled switches, they pass through a stop for each one.
Use the disabled attribute on a native checkbox or button switch, which removes it from the tab order. On a switch built from another element, set tabindex="-1" while aria-disabled="true" is set, and restore tabindex="0" when it becomes available.
Severity: Minor
Element that carries role receives focus
Reported as: Focusable offset
A switch must receive focus on the element that carries the switch role, not on one of its descendants.
When focus lands on a child of the element with role="switch", such as its thumb or its On and Off text, assistive technology describes that child, which has no role or state. Users tabbing through the page aren't told they've reached a switch or whether it's on.
Build the switch on a native checkbox or button, or add tabindex="0" to the element with the role, 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
Users expect a switch to turn an option or setting on or off, one they can easily turn back. They expect the switch to still be there after they toggle it, with focus still on it, and they don't expect it to take them anywhere else. Turning on dark mode, for example, restyles the page and leaves users where they were.
Keeps context when a value changes
Reported as: Unexpected context change on input
Changing a switch's state must not change the context unless users are told beforehand that it will.
When toggling a switch reloads the page, submits a form, opens a dialog, or moves focus, 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.
Apply the setting in place and leave focus on the switch. When the change of context is intended, say so in text that comes before the switch.
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 switch turns on or off each time the user clicks it or presses Space while it has focus, and the state it reports changes with it. A switch that isn't a native checkbox responds to Enter too. Only the state changes: the accessible name stays the same.
A native checkbox switch manages its state through its checked property, so it shouldn't also carry aria-checked. Any other switch updates aria-checked in the same code that changes how it looks, and ignores activation while it's disabled.
Updates the state on activation
Reported as: Element's state did not change
Activating a switch built from a button or a non-semantic element, with a pointer or the keyboard, must update aria-checked to its new state.
When the thumb moves but aria-checked keeps its starting value, sighted users see the switch toggle while assistive technology reports the old state. A screen reader user who turns the setting on hears no change and, returning to it later, is told it's still off.
Derive aria-checked and the switch's appearance from the same state, and write both in one place. Handle every activation 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 switch 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 switch reports the right state once and then stays there. A user who turns the setting off is told it's still on, 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 checkbox switch must not also carry aria-checked.
When an <input type="checkbox"> with role="switch" 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 switch the user has just turned on can be reported as off.
Remove aria-checked from the native checkbox and let checked report the state. Keep aria-checked for a switch built from a button or another element, which has 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. |
Keeps a stateful name in step
Reported as: Toggle name not resetting
A switch's accessible name must never report a state the switch isn't in.
When the visible On or Off text inside a switch is part of its accessible name and updates only on the first toggle, the name then contradicts the state. Screen reader users hear "Dark mode on, switch, off" and can't tell which to believe. Voice control users who say what they hear may not reach the switch.
Hide the On and Off text with aria-hidden="true", so the name stays fixed and aria-checked or checked reports the state.
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 switch that presents as disabled must not change state when it's activated.
When a switch built from a non-semantic element carries aria-disabled="true" but keeps its click and key handlers, activating it still toggles aria-checked. Screen reader users hear the switch announced as unavailable and then hear its state change, so they can't trust either signal or tell whether the setting changed.
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 or button, 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 switch 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 switch'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 switch 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 switch issues relate to?
Most relate to 4.1.2 Name, Role, Value: the switch's role, its accessible name, its on or off state and the values it takes, how it conveys a disabled state, updating and reversing that state on activation, keeping its name in step with its state, and keeping other interactive elements out of it.
Reaching the switch 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 switch that still changes state to 1.3.1 Info and Relationships.
Taking a disabled switch out of the tab order maps to no WCAG success criterion and is a best practice.
Why are some switch issues marked as Critical and others as Minor?
Severity reflects how much an issue gets in users' way. Critical issues stop users outright: a switch 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 on state the switch doesn't have, letting its name contradict the state, nesting controls, or changing the context without warning.
An invalid aria-checked value, or a disabled switch that still toggles, is Moderate. A disabled switch left in the tab order, or focus that lands inside the switch 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
- Checkbox: marks an option or set of options as chosen or not, and can be mixed
- Toggle Button: a button that can be pressed or not, which takes an action rather than setting a value
- Radio Group: a set of options from which only one can be chosen
- Button: performs an action or command rather than setting a value