Paweł Ludwiczak
Posted on April 8, 2022
Intro
Toggle is a TRUE/FALSE switch that looks like a... switch... Similar control you can find in your smartphone settings probably.
Under the hood, since it's a TRUE/FALSE type of a control, it's basically just a more fancy styled input[type="checkbox"]
.
And here's why it's tricky to make it accessible.
Usual way
Usually, to build such a toggle with HTML & CSS you need a visually hidden checkbox within a fancy styled label
element. And that's what most of the tutorials will tell you.
label
element makes sure that the entire toggle is "interactive" (i.e. clickable).
You can't just hide the checkbox with display: none
because it would make it invisible to assistive technologies. So here's the trick to make it invisible to screens yet accessible:
label.toggle {
position: relative;
...
[type="checkbox"] {
position: absolute;
left: -10000px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
}
...
}
The Problem and The Solution
And here's a caveat: our toggle (which is a checkbox) is wrapped with label
therefore it's required (by the a11y police 👮) to provide an actual text description. But we don't want our component to dictate how that text description should look like... Because it might be used in several different ways:
- sometimes text might be in front of a toggle, sometimes after it, and sometimes above it,
- sometimes text might be longer and styled and sometimes not.
Hence we can't use label
🤷♂️. But if we use regular div
or span
instead, then we lose the "clickability" of our toggle.
So the actual trick is to enlarge the checkbox to be as big as the toggle wrapper (that div
or span
) and hide it differently:
div.toggle {
position: relative;
...
[type="checkbox"] {
width: 100%;
height: 100%;
opacity: 0.00001;
...
}
...
}
First we make sure checkbox takes full width and height. Then we almost hide the checkbox with opacity: 0.00001;
.
Opacity can take values between 0
(fully invisible) and 1
(fully visible). We use value very close to 0 so it's basically invisible on the screen but visible to assistive technologies.
That's it folks. Below is a full demo :)
^ try to remove that opacity property to see the actual checkbox placement.
Couple notes:
- You could practically use any element to create toggle if you also sprinkle it with JS. But I wanted to avoid it.
- Keep in mind, all form elements should be placed inside
label
, but in the World of Components, we don't really want such a low-level component to dictate how everything around it should look like. Components should be self-contained and not affect its surroundings (at least that's my philosophy).
Posted on April 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.