WebDev Workshop logo

WebDev Workshop

tools, code, and books to take your web development skills to the next level

A common element in many web apps is the toggle button (also called a toggle switch or just a toggle), which enables the user to turn a setting or option on or off. Yes, you could use a checkbox for that, but a toggle button adds visual interest because it includes a “switch” that slides right and left to indicate the button is on and off. Here’s an example:

Note that when you click the toggle button to the “on” position, not only does the switch slide to the right, but the background color also changes to give the user a visual indication of the state change. Here’s the code:

In the HTML Editor, we have a div element that serves as the toggle button’s label (and, as you’ll see, the text changes to indicate the current state of the toggle button). The toggle itself is composed of two elements: an input element with type="checkbox". We don’t use this checkbox directly, however, so it’s hidden via class="hide-me" (described below). The toggle button itself is given by the label element, which is tied to the checkbox using for="cb-toggle" (which is the id value used by the input element) and class="toggle" (also described below).

Now let’s check out the CSS:

Lines 1-10:
.toggle {…
Styles the toggle button (that is, the <label class="toggle"> tag).
Line 2:
position: relative;
Sets up a positioning context for the ::after pseudo-element (discussed below).
Lines 3-5:
display: inline-block;…
Converts the element to a block and sets the element’s width and height.
Line 6:
background-color: hsl(0, 0%, 85%);
Sets the initial color of the toggle button background. The toggle starts in the off position, so the initial color is the “off” background color, which is a light grey.
Line 7:
border-radius: 25px;
Rounds the corners of the toggle button frame.
Line 8:
cursor: pointer;
Changes the mouse cursor to a pointing finger when the user hovers the cursor over the toggle button.
Line 9:
transition: background-color 0.25s ease-in;
Sets the parameters of the animation that runs for the background-color value, which changes when the button is toggled (see line 23).
Lines 11-21:
.toggle::after {…
Defines and styles a pseudo-element that comes after the toggle button’s frame and is used to style the button's switch.
Line 12:
content: '';
The pseudo-element is defined without any content.
Lines 13-15:
position: absolute;…
Set the switch to use absolute positioning within the toggle button and positions the switch with a 2px offset from the top left of the toggle.
Lines 16-17:
width: 22px;…
Set the width and height of the switch.
Line 18:
background-color: white;
Sets the background color of the switch to white.
Line 19:
border-radius: 50%;
Rounds the corners of the switch into a circle.
Line 20:
transition: all 0.25s ease-out;
Sets the parameters of the animation that runs when the button is toggled. In this case, the transform property (see line 28) shifts the switch right (when it’s on) and left (when it’s off).
Line 22:
#cb-toggle:checked + .toggle
Selects the toggle button (the toggle class) when the checkbox element (#cb-toggle) is checked.
Line 23:
background-color: hsl(102, 58%, 39%);
Sets the background color of the toggle button to green when the button is toggled to the “on” position.
Line 25:
#cb-toggle:checked + .toggle::after
Selects the toggle button’s switch (the toggle::after pseudo-element) when the checkbox element (#cb-toggle) is checked.
Line 28:
transform: translateX(24px);
Shifts the switch 24px to the right when the button is toggled to the “on” position. Lines 26 and 27 are the vendor-prefixed versions of the transform property;
Lines 30-33:
.hide-me…
Hides an element (in this example, the checkbox) by setting its opacity, height, and width to 0.
Tip

If you prefer a rectangular button, either remove the border-radius property from both the .toggle rule and the .toggle::after rule, or set this property to 0 in both places. Either way, you return both elements to their default square corners.

Note

I won’t go through the details here, but the JavaScript tab includes a script that adds a click event listener to the checkbox element. When a checkbox click event occurs, the event handler examines the current state of the checkbox: if it’s checked, the script changes the current state value (represented by the span element embedded in the div element) to on; otherwise, it’s set to off.

Note

The “trick” in this technique is that when you’re working with a checkbox element, the browser toggles the checkbox when the user clicks either the checkbox itself or the checkbox label as defined by the label element. That’s why we can hide the checkbox, yet still toggle it on and off because the label is still visible. However, the label element is no longer pulling its semantic weight because we’ve styled it to look like a toggle switch, so it no longer serves to label anything. That’s a big accessibility no-no because screen readers and other software that parse the page won’t have a label for the switch. To fix that, I’ve given the div element id="cb-label" and added the aria-labelledby="cb-label" to the checkbox element. This tells parsing software which element in the page is acting as the checkbox label.

Text is Copyright Logophilia Limited.
Code is licensed under a  Creative Commons Attribution 4.0 International License.
Hand-crafted by Paul McFedries.