A sweet toggle switch


In today’s world of front-end web development, it’s becoming increasingly complex to create custom interface elements. A common scenario is when your design team has required a non-standard web-based form component. This time it’s a toggle switch which seems to be becoming more popular in the web design world.


Winging the development of a toggle switch for a prototype is one thing, but for production a gracefully degradable and fully accessible version is required. Let’s walk through the strategy and code for developing a sweet toggle switch. We’ll create a control where the user can select either a “checking” or “savings” account.

Coding Strategy

As we should with any front-end project, let’s start with HTML semantics. Because the switch is essentially selecting between two options, let’s use two radio inputs each of course with a label. Using basic form elements will also make submitting the form simple and not require any scripting. At first glance, it may seem that a single checkbox element may work; but two labels are required, and the form data to be passed may need to be more than a simple Boolean value. The radio inputs and labels are contained in a div and then within a form. The labels are styled to create the toggle switch effect. Paragraph text provides the instructional text which tells the user what the toggle switch is for.

Marking It Up

Below is an example of the basic HTML. The checked attribute is optional; if removed, the toggle switch renders as expected on page load (neither option selected). The labels will be floated left in the next step, so a “clearfix” class is added to the container. The radio inputs are hidden visually using an “accessAid” class (which uses the clipping technique to hide rather than off-screen).

  <p>Select the type of account:</p>
  <div class="toggle-btn-group clearfix">
    <input type="radio" id="checking" name="accountType" value="checking" class="accessAid" checked="checked" />
    <label for="checking">Checking</label>
    <input type="radio" id="savings" name="accountType" value="savings" class="accessAid" />
    <label for="savings">Savings</label>

For accessibility and structure, sets of radio or checkbox elements many times require a fieldset and legend elements or an ARIA substitute. But in this case, it’s not needed because the labels by themselves are clear. Web accessibility experts at WebAIM say “basic radio buttons (such as male/female for gender) that make sense from their labels alone do not require fieldset and legend.” If a use case requires the added clarification of the controls, use the aria-describedby attribute. Here’s an example:

<p id="p1">Select the type of account:</p>
  <div class="toggle-btn-group clearfix">
  <input type="radio" id="checking" name="accountType" value="checking" class="accessAid" checked="checked" aria-describedby="p1" />


The CSS of course will transform the appearance of the radios to a toggle switch; well, more accurately, the radio inputs are visually hidden and their labels create the visual effect.

.toggle-btn-group label {
  padding: .5em;
  display: inline-block;
  width: 8em;
  float: left;
  text-align: center;
  cursor: pointer;
  color: #000;
  background-color: #ddd;
  border: #999 2px solid;

Rounded corners are added to create the pill-like shape.

.toggle-btn-group label:first-of-type {
  border-top-left-radius: .5em;
  border-bottom-left-radius: .5em;
.toggle-btn-group label:last-of-type {
  border-top-right-radius: .5em;
  border-bottom-right-radius: .5em;

With some fun CSS selectors, the selected/checked state of the label is created through the “checked” pseudo class of the associated radio element (the adjacent sibling). The focus state is normally indicated by the radio inputs; but since they are visually hidden, we return that functionality.

.toggle-btn-group input[type="radio"]:checked+label {
  background-color: #00a1ff;
  border: #000 2px solid;
  color: #000;
.toggle-btn-group input[type="radio"]:focus+label {
  outline: 2px #999 dotted;

And then the default hover and focus states.

.toggle-btn-group label:hover,
.toggle-btn-group label:focus {
  background-color: #ccc;
  border: #000 2px solid;
  color: #000;

Falling Back and IE8

In modern browsers, JavaScript is not required so the toggle switch will function fine when JavaScript is not available. If CSS is not available for any reason, the toggle switch simple renders as the basic radio inputs with the associated text labels.

Internet Explorer versions 8 and below do not support the checked CSS pseudo-class selector (input[type="radio"]:checked+label). To make it work, JavaScript is required. A listener on the labels can be implemented to add and remove another class which gives the same styling.

Putting it all together

You can view an example of this toggle switch here. Feel free to model the code and share with your peers.


Native web components are always the best way to go. But when it’s not possible due to design requirements, there’s usually a good way to solve while keeping degradation and accessibility in mind. In the toggle switch example, we started with fundamental radio inputs within a form and enhanced the design with CSS.

Thanks to fellow PayPals Victor Tsaran and Dereck Quock for input in this article.

Dennis Lembree

Mr. Lembree is a MTS1 User Interface Engineer on the accessibility team at PayPal. He's previously worked for several start-up companies and contracted at Google, Ford, and Disney. His personal projects include EasyChirp.com, an award-winning Twitter app, and WebAxe.org, a blog/podcast on web accessibility. He resides in Cupertino, California with his wife and two boys.