Toggle Buttons / Switch
A toggle button is a component that has two possible states – on and off. The state is defined using
aria-pressed
attribute.
NOTE:
- New to accessibility or uncertain of requirements, it will be helpful to review all sections below.
- Already familiar with requirements, skip to the “Working Example” section for sample HTML, CSS and JavaScript (when needed), along with a working demo.
-
The toggle button text MUST be at least 4.5:1 against the background color if it’s a
standard text in default, focused and hover state.
- The minimum contrast requirement ratio of 3:1 for the large text or text with 14pts and bold MUST be met in default, focused and hover state.
- The contrast requirement of 3:1 ratio MUST be met with the adjacent colors for the custom focus indicator of the toggle button.
- The contrast ratio requirement of 3:1 MUST be met with the adjacent colors for the toggle button in default, pressed, unpressed, focused and hover state.
-
Only color MUST not be used to distinguish the pressed and unpressed state of the buttons.
- There SHOULD be a visual cue like underline, bold formatting or so on that be used to help indicate the pressed state of the toggle button visually.
- The toggle button SHOULD be defined using
<button>
element. -
To indicate the state,
aria-pressed
attribute SHOULD be defined for the<button>
element.-
The value of
aria-pressed
MUST be set to true in on state and false in off state.
-
The value of
-
Alternatively, native HTML checkbox
<input type="checkbox">
CAN be used to implement a toggle control.- CSS can be used to keep the visual presentation as a toggle button and hide the checkbox control from users visually.
-
Another alternative way to implement a toggle button is by providing
role="switch"
on the<button>
element.-
To indicate the state programmatically,
aria-checked
SHOULD be provided for the<button>
element. -
The value of
aria-checked
SHOULD be set totrue
in ON state andfalse
in OFF state.
-
To indicate the state programmatically,
- A descriptive and programmatic label MUST be provided for the toggle button. See “Label placement and structure” component for more information on labelling.
For example,
<!-- Toggle button unpressed state -->
<button type="button" id="ex1-toggle" aria-label="Mute" aria-pressed="false">...</button>
<!-- Toggle button in pressed state -->
<button type="button" id="ex2-toggle" aria-label="Mute" aria-pressed="true">...</button>
<!-- Toggle button with role="switch" in unchecked state -->
<span id="ex1-auto_sign">Auto Sign-in </span>
<button type="button" id="ex1-toggle2" role="switch" aria-labelledby="auto_sign" aria-checked="false">
<span>on</span><span>off</span>
</button>
<!-- Toggle button with role="switch" in checked state -->
<span id="ex2-auto_sign">Auto Sign-in </span>
<button type="button" id="ex2-toggle2" role="switch" aria-labelledby="auto_sign" aria-checked="true">
<span>on</span><span>off</span>
</button>
A well-defined toggle button benefits majorly the below users.
- People with cognitive disabilities
- People using speech input
- People with limited dexterity
- People using keyboard only
- People with visual disabilities
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"/>
<h4>Using &#lt;button&#gt; element with aria-pressed attribute</h4>
<button id="playButton" aria-pressed="false" aria-label="Play">
<i class="fas fa-volume-up" aria-hidden="true"></i>
</button>
<button id="muteButton" aria-pressed="false" aria-label="Mute">
<i class="fas fa-play" aria-hidden="true"></i>
</button>
<h4>Using <button> element with role="switch" and aria-checked attribute</h4>
<div>
<span id="auto_sign">Auto Sign-in </span>
<button type="button" id="toggle2" role="switch" aria-labelledby="auto_sign" aria-checked="false">
<span>on</span><span>off</span>
</button>
</div>
<div>
<span id="payment_methods">Save and fill payment methods </span>
<button type="button" id="toggle1" role="switch" aria-labelledby="payment_methods" aria-checked="false">
<span>on</span><span>off</span>
</button>
</div>
button {
border: none;
background-color: transparent;
cursor: pointer;
}
button i {
font-size: 24px;
}
#muteButton[aria-pressed="true"] i::before {
content: "\f6a9"; /* FontAwesome icon for pressed state */
}
#muteButton[aria-pressed="false"] i::before {
content: "\1F508"; /* FontAwesome icon for unpressed state */
}
#playButton[aria-pressed="true"] i:before {
content: "\f144"; /* Play icon */
}
#playButton[aria-pressed="false"] i::before {
content: "\f04c"; /* FontAwesome icon for unpressed state */
}
:root {
--brightest: #fff;
--bright: #757580;
--positive: #003057;
}
[role="switch"] {
padding: 0;
width: 2.6rem;
height: 1.5rem;
border: 0;
border-radius: 1rem;
background-color: var(--bright);
}
[role="switch"][aria-checked="true"] {
background-color: var(--positive);
}
[role="switch"] span {
color: var(--brightest);
padding: 0.1rem;
pointer-events: none;
border-radius: 2rem;
}
[role="switch"][aria-checked="false"] :last-child {
padding-left: .2em;
}
[role="switch"][aria-checked="true"] :last-child,
[role="switch"][aria-checked="false"] :first-child {
background: var(--brightest);
}
label {
font-size: 18px;
}
div {
display: block;
margin: 1rem;
}
[role ="switch"]:focus {
outline: .18em solid #000;
outline-offset: 1px;
}
let muteButton = document.getElementById("muteButton");
let playButton = document.getElementById("playButton");
let isMuted = false;
let isPlaying = false;
muteButton.addEventListener("click", () => {
isMuted = !isMuted;
muteButton.setAttribute("aria-pressed", isMuted);
});
playButton.addEventListener("click", () => {
isPlaying = !isPlaying;
playButton.setAttribute("aria-pressed", isPlaying);
});
let togglebtn2 = document.querySelector('button#toggle2');
togglebtn2.addEventListener('click', (e) => {
let el = e.target;
let state = el.getAttribute('aria-checked');
let isState = (state === 'true');
el.setAttribute('aria-checked', isState ? false : true)
});
let togglebtn1 = document.querySelector('button#toggle1');
togglebtn1.addEventListener('click', (e) => {
let el = e.target;
let state = el.getAttribute('aria-checked');
let isState = (state === 'true');
el.setAttribute('aria-checked', isState ? false : true)
});
Using <button> element with aria-pressed attribute
Using <button> element with role="switch" and aria-checked attribute
Auto Sign-in
Save and fill payment methods