JavaScript Keyboard Accessibility

Share this article

The following is republished from the Tech Times #161.

JavaScript accessibility is an issue fraught with controversy and imperfect solutions, particularly when it comes to supporting the screen reader software that many visually impaired users rely on. These difficulties have led many developers to give up on accessibility entirely, when making your JavaScript accessible to some users can be refreshingly straightforward!

One group of users that it’s often very practical to accommodate in your JavaScript-powered web applications is keyboard users. Often due to a lack of fine motor control, these users get by without a mouse and instead navigate around the Web using the keyboard.

Let’s look again at the accordion control that I introduced in Tech Times #159, and see how we can make it work for keyboard users.

Here’s what the structure of the accordion’s HTML looks like:

<ul class="accordion">
  <li>
    <h2>Jonathan Archer</h2>
    <p>Vessel registry: NX-01</p>
    <p>Assumed command: 2151</p>
    ...
  </li>
  ...
</ul>

The way this control works for mouse users is that the heading of each fold of the accordion is clickable:

var folds = accordion.getElementsByTagName("li");
for (var i = 0; i < folds.length; i++)
{
  var foldTitle = folds[i].getElementsByTagName("h2");
  addEvent(foldTitle, "click", Accordion.clickListener);
}

When the user clicks one of these headings, a function is called that expands the corresponding fold, and collapses all the others:

clickListener: function(event)
{
  var fold = this.parentNode;
  Accordion.expand(fold);
  preventDefault(event);
},

Now, let’s think about how this script will affect keyboard users. The script collapses the accordion when the page first loads, hiding its contents. As it stands, keyboard users have no way of accessing that collapsed content.

Mouse users can click on any element in the document, but keyboard users can only “click” on keyboard-focusable elements. Typically, a keyboard user will repeatedly hit the Tab key (or the A key in Opera) to move the keyboard focus to the desired element, then hit Enter to initiate a “click”. By default, however, headings like the <h2> tags in our accordion are not keyboard-focusable.

To overcome this issue, you need to do one of two things:

  • Make the non-keyboard-focusable element keyboard-focusable.
  • Add to the document an element that is keyboard-focusable, like a hyperlink.

The first option would be ideal—in a perfect world. In Firefox 1.5 or later and Internet Explorer 5 or later, you can set the tabIndex property of a non-keyboard-focusable HTML element to zero, and it will magically become keyboard focusable. Unfortunately, this trick is not specified in any standard, and isn’t supported by other browsers like Safari and Opera.

The alternative, thankfully, works well enough in most situations: just add a hyperlink to the document where you want keyboard users to be able to focus and click.

Elegant as this solution is, there is one issue to consider: what URL is the link going to link to? If you insert the link directly into your HTML code, it needs to link someplace that will make sense when JavaScript is disabled:

<ul class="accordion">
  <li id="archer">
    <h2><a href="#archer">Jonathan Archer</a></h2>
    <p>Vessel registry: NX-01</p>
    <p>Assumed command: 2151</p>
    ...
  </li>
  ...
</ul>

If you can’t figure out an appropriate target for the link, however, you can always insert the link into the page dynamically using JavaScript, so that it will not be present when JavaScript is disabled. If you do this, you can safely point the link just about anywhere ("#" and "javascript:;" are common choices).

You can now adjust your JavaScript code to listen for “clicks” (both the mouse and keyboard varieties) on the link instead of the heading:

var folds = accordion.getElementsByTagName("li");
for (var i = 0; i < folds.length; i++)
{
  var foldLinks = folds[i].getElementsByTagName("a");
  var foldTitleLink = foldLinks[0];
  addEvent(foldTitleLink, "click", Accordion.clickListener);
}

A minor change to the clickListener function will also be necessary to account for the added depth of the clicked element:

clickListener: function(event)
{
  var fold = this.parentNode.parentNode;
  Accordion.expand(fold);
  preventDefault(event);
},

In many real-world scripts, providing accessibility for keyboard users really can be that easy.

Kevin YankKevin Yank
View Author

Kevin Yank is an accomplished web developer, speaker, trainer and author of Build Your Own Database Driven Website Using PHP & MySQL and Co-Author of Simply JavaScript and Everything You Know About CSS is Wrong! Kevin loves to share his wealth of knowledge and it didn't stop at books, he's also the course instructor to 3 online courses in web development. Currently Kevin is the Director of Front End Engineering at Culture Amp.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week