Tag Archives: semantics

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.

Interactive elements within a grid layout


Often times, the best way to begin marking up HTML content is to put aside the visual design and concentrate on the semantics. A good example of this is when a design first appears to be a data table but actually includes content other than data.

The Challenge

In the following wireframe design, transaction records are displayed in a table-like format, a grid. Each row is designed to be a link (the entire row) and has a grey hover/focus effect. Data includes a date, description, and dollar amount. There is also a menu button in each of the records; clicking it opens a drop down menu.

Screenshot of layout grid

At first glance, the design appears to be a data table. But the row link and the menu button within a data table create fundamental markup and accessibility issues. (If the design called for traditional text links instead of the row link and menu button, a data table is a solid option.) A layout table would create similar issues as a data table but we’re not going to go there in the name of Web Standards.

First Approaches

Definition List

One idea for marking up this content is to use a description list. For each row, a unique identifier (like a record number) would be the DT and would be visually hidden. The rest of the row content would be contained in DD elements. Example:

  <dt>Record 1</dt>
  <dd>[menu button]</dd>

But like the table, the row link would certainly be challenging, and would add to the complexity of the extensive CSS already required to make this fit the visual design. Also, the menu button doesn’t fit the semantic meaning of a DD (description data).


Another approach is to use divs and spans with the ARIA grid role along with the associated row and gridcell roles. In this technique, “the grid construct describes relationships between data such that it may be used for different presentations”. In other words, a more flexible data table-like structure can be developed. Example:

<div role="grid">
  <div role="row">
    <a href="#">
      <span role="gridcell" class="date">date</span>
      <span role="gridcell" class="desc">description</span>
      <span role="gridcell" class="price">amount</span>
    <span role="gridcell" class="menu">[menu button]</span>

To give context to screen reader users, it may be a good idea to add the aria-labelledby property and the rowheader and columnheader roles.

The main problem with this technique is support. ARIA is still relatively new, and inconsistent results are found among the different screen readers (JAWS, NVDA, VoiceOver). There is also a lack of semantic elements, and the abundance of ARIA creates code complexity (especially to those not yet familiar with ARIA).

A Solution

Let’s take a step back and simplify. There are three main piece to the puzzle: a unique identifier (not in visual design), some linked text, and a menu button.

One feasible solution is to use:

  • a heading as the unique identifier for each record (like the DT in the example above), 
  • an anchor element containing spans for the link (like the ARIA example above), 
  • a div to contain the menu button.

Divs are also used for CSS hooks in order to create the grid/table-like design. Example:

<div class="table">
  <div class="tableRow">
    <h3>Record 1</h3>
    <div class="tableRowInner">
      <a href="foo.html">
        <span class="tableColumn date">date</span>
        <span class="tableColumn desc">description</span>
        <span class="tableColumn price">amount</span>
    <div>[menu button]</div>

For the title of the grid content, let’s use a heading, say an H2 in this case. For proper heading levels, each record will then require an H3 heading. This is great for not only page structure but also helps screen readers users for context and navigation. The menu button is separated in its own Div but still falls under the record’s H3 heading.

Using CSS we create the grid design. Here’s an excerpt:

.tableRow .tableColumn {
  display: block;
  float: left;
  color: #333;
.tableRow .tableRowInner > a {
  display: block;
  float: left;
  padding: .75rem 0;
  text-decoration: none;
  width: 118%;
.tableRowInner {
  float: left;
  width: 85%;
.tableRow:last-child .tableRowInner {
  padding-bottom: 1.5em;
.tableRow .tableColumn.date {
  width: 25%;
.tableRow .tableColumn.desc {
  width: 40%;
.tableRow .tableColumn.price {
  text-align: right;
  width: 25%;

With some CSS magic, we can position the menu button to appear within the row (check the widths of the row and anchor). And there we have it; a grid layout with interactive elements which is accessible. It also a robust solution; it functions well without JavaScript or without CSS.

Check out the working example

Final Words

Developing ideal solutions can be difficult in these days of complex web apps, stringent design requirements, and increasing accessibility concerns. The solution in this article isn’t perfect (could use less divs and spans and more semantic elements), but it certainly does the job. Do you have any suggestions for this issue?