🤯 New: Coding Assessments Practice your skills on real-world programming challenges

JavaScript and Screen Readers

    Kevin Yank

    The following is republished from the Tech Times #163.

    Try to use one of the poster-child Ajax web applications like GMail with a screen reader and you’ll never want to touch a screen reader again. To support those users who don’t have that luxury, then, do you have to do without JavaScript?

    The answer to this question ultimately depends on the sort of web application you need to build. Of course, if you’re developing something as silly as a web-based version of Photoshop, you can probably rule out screen reader support at the outset.

    Most web applications, however, will fall into a gray area where it’s possible to support screen readers—even without sacrificing any of the JavaScripty goodness you want to deliver to the rest of your user base. The question then becomes, is it practical?

    A Practical Example

    Setting aside the likes of GMail for the moment, let’s look again at the accordion control that’s built as an example in my upcoming book.

    A couple of issues back, we modified this example to make it accessible to keyboard users. All we had to do was include a hyperlink in the heading of each section of the accordion so that it would be keyboard-focusable. As we’ll see, making this construct accessible to screen reader users is equally straightforward—it’s doing both at once that’s a little tricky!

    To refresh your memory, here’s what the HTML code for this page looks like:

    <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>

    If that’s all there were to this page, it would be perfectly accessible to screen readers. We only get into trouble when our JavaScript code hides portions of the page content by dynamically setting a class of "collapsed" on the list items that make up the accordion. This class hides all but the heading inside the list item:

    li.collapsed * {
      display: none;
    li.collapsed h2,
    li.collapsed h2 a:link, li.collapsed h2 a:visited {
      display: block;

    The problem here is that using display: none to hide an element from view also hides the element from screen readers, and screen reader users are unable to read that portion of the page.

    Of course, this might not be an issue if revealing the elements by switching off the "collapsed" property also revealed those elements to screen reader users. Were that the case, screen reader users could use the accordion just as other users do: by “clicking” a header in the accordion to reveal its contents.

    As it turns out, however, this is not always the case. Most screen readers work with a static copy of the page’s visible contents—a copy that is infrequently and unpredictably updated (despite early signs from some vendors that this may be changing). And even in screen readers that do refresh their copy of the page contents in response to the user clicking a link, making the user aware that the content has been revealed is problematic at best.

    No, your best bet in this case is to hide the contents of the collapsed accordion in such a way that screen reader users are still able to read them. The most useful technique to do this is called offleft positioning, and the CSS code looks like this:

    li.collapsed * {
      position: absolute;
      left: -9999px;
    li.collapsed h2,
    li.collapsed h2 a:link, li.collapsed h2 a:visited {
      position: static;

    In essence, this technique hides elements of the page by positioning them off the left of the page (9999 pixels off the left of the page, to be precise), where they will still be visible to screen readers.

    So now screen reader users can read the entire content of the page without any interference from our JavaScript-driven accordion effects! Problem solved, right?

    Well, not quite. You see, offleft positioning not only reveals the hidden elements to screen readers—it makes them available to keyboard users as well! In this case, when a keyboard user taps the Tab key to step through the focusable elements in the page, the focus will also step through any hyperlinks in our hidden content. Since these elements are invisible, the keyboard focus will seem to disappear, leading to angry phone calls.

    Since there’s no reliable way to hide elements from keyboard users without also hiding them from screen reader users, we need to take a different approach. How about we do something useful when keyboard focus is given to a hidden element … like expanding the relevant section of the accordion!

    We can add to every focusable element within the accordion (except, of course, the links in the always-visible headers) a focus event listener:

    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);
      for (var j = 1; j < foldLinks.length; j++)
        addEvent(foldLinks[j], "focus", Accordion.focusListener);

    When triggered, that focusListener function will expand the section of the accordion that contains it:

    focusListener: function(event)
      var element = this;
      while (element.parentNode)
        if (element.parentNode.className == "accordion")
        element = element.parentNode;

    And there you have it—an accordion control that is accessible to both keyboard and screen reader users!

    More Complex Cases

    As you might expect, not all JavaScript enhancements can be adapted to avoid interference with screen readers and keyboard navigation. Sometimes, the best you can do is make it easier for these users to disable the stuff that won’t work for them.

    In a recent blog post, for example, Jeremy Keith applauds Dan Champion‘s new social book review site, Revish, which offers users the option of disabling the Ajax features of the site that won’t work with screen readers when they sign up for an account. This solution is nice and slick, allows the user to feel in control, and is extremely easy to implement, too!