Douiri

Toggle Switches - What are They and How to Make Them Accessible for The Web

written by idriss douiri profile picture Idriss Douiri

4 min read

share
an active toggle switch with blue accent color

We interact with toggle switches in every GUI and every platform. Unfortunately, web browsers don’t have native support for them yet.

Safari 17.4 has an experimental switch attribute that we can add to a checkbox input like this:

<input type="checkbox" switch />

This will make it easier for us as web developers. But as I said, it’s still experimental. so we have to build it ourselves and make sure it’s accessible.

What is a Toggle Switch?

A toggle switch is a form component that can be one of two states (On/Off, True/False).

But isn’t it just another checkbox? no, the differences between the two are covered later in this article

Toggle Switch Components

Switch toggles consist of two components:

  • The Track: which is the slider the thumb moves on.
  • The Thumb: the indicator that shows the current state of the switch.

toggle switch components named

The States of a Toggle Switch

When designing and building a switch component we need to consider these 4 states for a better user experience:

  • On state: The switch is active or checked.
  • Off state: The switch is inactive or unchecked.
  • Focused state: indicates which switch the user is interacting with.
  • Disabled state: The switch is non-interactive and cannot be toggled (read-only).

all toggle switch states: On, OFF, Focused, and Disabled

Toggle Switches VS Checkboxes

use canse of checkboxs vs toggle switches side by side

While switches and checkboxes might look similar there are some differences between the two depending on the use case, the following table highlights their key differences:

CheckboxSwitches
Select items from a list of elementstoggle between two states
Checking independent elementsGive instant feedback to the users
Requires manual saving for the change to apply

How to build a Toggle Switch?

HTML Markup:

Starting with HTML, we will use a checkbox input, which has some accessibility features built into it. So no Javascript is needed to manage the pressing or the state.

We also need to set the attribute role="switch" for assistive technology to know that this is a switch component and not a checkbox. The code will be:

<label>
	Show Captions
	<input type="checkbox" role="switch" />
</label>

I also gave it a label to describe the functionality of the switch.

With that, we are done with HTML and let’s move on to styling.

CSS:

In our CSS we need to style two things:

  1. Styling the checkbox to be the track.
  2. Styling a pseudo-element (::before or ::after) to be the thumb.

First, let’s target the checkbox by the role attribute using the attribute selector, this will ensure the existence of this attribute as it’s so important, and the styles won’t work if we miss it.

[role="switch"] {
	/* styles for track will go here */
}
[role="switch"]::before {
	content: "";
	/* styles for the thumb will go here */
}

To style the checkbox as we want we first need to set its appearance property to none, This will remove its default styling giving us the freedom to make it however we want.

Here are the styles for the switch track:

[role="switch"] {
  --padd: 0.5em;
  --track-width: 19em;

  appearance: none;
  display: inline-grid;
  background-color: #607d8b;
  width: var(--track-width);
  height: calc(var(--track-width) / 2 ); 
  border-radius: 9999px; /* to make it a pill shape */
  padding: var(--padd);

  cursor: pointer;
  transition: background-color 300ms;
}

To position the thumb inside the switch we can use the position property, however in this case I went with a display of grid which will place the pseudo-element inside the input.

Now let’s style the ::before pseudo-element to be the thumb for our switch like this:

[role="switch"]::before {
    content: "";
    /* make it a circle */
    width: calc(var(--track-width) / 2);
    height: calc(var(--track-width) / 2);
    border-radius: 50%;

    background-color: #eceff1; /* the color of the thumb */
    box-shadow: 0 0 10px #444a;

    transition: transform 300ms, box-shadow 150ms ease-in-out;
  }

Styling different states:

Now the switch is looking good but we can’t tell whether it’s On or Off, to fix this we will style the switch based on its :checked pseudo-class:

[role="switch"]:checked {
    background-color: #00bfa5;
}
[role="switch"]:checked::before {
     /* place the thumb at the other side on checked */
      transform: translateX(calc(100% - var(--padd) * 2));
}

For the hover and focus states, I will show a ring over the thumb using the box-shadow property like this:

[role="switch"]:hover::before,
[role="switch"]:focus-visible::before {
    box-shadow: 0 0 0 1.5em #cfd8dc90;
}

Lastly, let’s check whether the input is disabled and style it accordingly.

In HTML we can disable the checkbox by by setting the disabled attribute like this:

<input type="checkbox" role="switch" disabled />

and style it based on its :disabled pseudo-class to indicate that this element is not interactive:

[role="switch"]:disabled {
    cursor: not-allowed;
    background-color: #cfd8dc;
}
[role="switch"]:disabled::before {
    background-color: #90a4ae;
    box-shadow: none;
}

Complete Code

Here is the final code example, make sure to edit the values to fit your design:

See the Pen toggle switch component by Driss (@driss-d) on CodePen.