Writing JavaScript with accessibility in mind

Tips on how to improve the accessibility of your JavaScript components and provide users with more and better ways to interact with your website or web app.

Manuel Matuzovic
11 min readFeb 12, 2017

In my first post Writing HTML with accessibility in mind I explained why and how I got started with web accessibility. I also shared some tips on how you can improve your markup in order to make your websites more accessible. Some of these were pretty basic but nevertheless valuable. It all boils down to two of the most important unwritten rules in front-end development: Learn the basics and take enough time to plan and write HTML. Both you and your users will benefit from clean and semantic markup.

Luckily, HTML is not the only language we have to make websites, but the more complex the language, the easier things can go wrong and JavaScript can get very complex. Whilst being content that our code works, it’s easy to forget about users with other input devices than a mouse or touch pad, e.g. keyboard or screen reader users. In this second article of four about web accessibility I have gathered some tips on what to consider when writing JavaScript and how to make your JavaScript components more accessible.

JavaScript is not the enemy

Before you read my tips I want to point out one important thing: Making an accessible site doesn’t mean that you have to decide whether to use JavaScript or not. Accessibility is about making content available to as many people as possible, which also includes users with old browsers and computers, slow internet connections, strict security restrictions (e.g. no JavaScript) and so on. The experience under conditions like these where JavaScript may not work or take too long to load might not be ideal but is still good enough if the website is accessible and usable.

If JavaScript is executable it can even be used to improve accessibility. Sara Soueidan has written about her experiences with creating a tooltip widget in „ Building a fully-accessible help tooltip …is harder than I thought.“. She explains how every „single no-JS solution came with a very bad downside that negatively affected the user experience“ and why JavaScript is important for accessibility.

Marco Zehe wrote a lot more about JavaScript and accessibility in JavaScript is not an enemy of accessibility!. I highly suggest you read his post.

But enough with the introductory talk! Have fun!

Great focus management is essential

It’s important to make sure that our websites are navigable by keyboard. A lot of users rely on a keyboard when they surf the web. Among them are people with motor disabilities, blind people and people who don’t have hands or cannot use a mouse or track pad for whatever reason.

Navigating a site via keyboard means jumping from one focusable element to another in DOM order. This is usually accomplished by using the Tab key or Shift + Tab for the reverse direction. Focusable elements are amongst others links, buttons and form elements. They can be selected with the Enter key and sometimes the Spacebar. By being focusable and selectable in different ways they come with very useful default functionalities. Therefore it just makes sense to use correct semantic elements and write HTML in a logical order.
Elements like <p>, <h2> or <div> cannot be focused by default. We often use tags like these to create custom components powered by JavaScript, which might be problematic for keyboard users.

Making non-focusable elements focusable

It’s possible to make non-focusable elements focusable by adding the tabindex attribute with an integer value. If the value is set to 0 the element becomes focusable and reachable via keyboard.
If the value is a negative number, the element is focusable (e.g. with JavaScript) as well, but not reachable via keyboard. You can also use a value greater than 0, but that changes the natural tab order and is considered an anti-pattern.

<h2 tabindex="0">A focusable heading</h2>

If you want to learn more about tabindex, watch the A11ycasts episode Controlling focus with tabindex by Rob Dodson.

Focusing elements with JavaScript

Even if elements are focusable, sometimes they are not in the right DOM order. To illustrate that I created a simple modal window component in HTML, CSS and JS (Demo and editable Pen).

If you use the Tab-key to jump to the button and press enter, a modal window will pop up. If you press the Tab-key again, the focus will jump to the next link visually below the modal window. The expected behavior would be that the next focused element is within the modal window. But it's not because elements are focused in DOM order and the modal window is located at the bottom of the document. You can see that in action in the following screen recording.

A short video which illustrates bad focus management.

To fix that you have to make the modal window focusable and then focus it with JavaScript.

HTML

// Add tabindex="0"
<div class="modal" id="modal2" tabindex="0">
...
</div>

Javascript

// Use the focus() method to set focus
function showModal() {
...
var modal = document.getElementById('modal2');
modal.focus();
...
}

You can see that in action in the updated example (Demo and editable Pen) by tabbing to the button, pressing enter and tabbing again. You’ll see that the modal window itself is focused now.
This is great, but there are still two issues here.

If you close the modal window by pressing Esc the focus is lost. Ideally, the focus would jump back to the button where it was before you opened the modal window. In order to achieve that you have to store the last focused element in a variable.

document.activeElement gives you the current element in focus.

// Variable for storing the last focused element
var lastFocusedElement;
function showModal() {
...
// Store the last focused element
lastFocusedElement = document.activeElement;
var modal = document.getElementById(modalID);
modal.focus();
...
}

Now that you have a reference to the button you can focus it again when the modal window is closed.

function removeModal() {
...
// Return the focus to the last focused element
lastFocusedElement.focus();
...
}

I’ve updated the code in another Pen (Demo and editable Pen). The accessibility is way better now, but there’s still room for improvement.

It’s advised to the keep the focus within the modal window when it’s opened. Right now it’s still possible to tab out of the modal.
I won’t go into detail here, but for the sake of completeness I made a fourth Pen with a so called keyboard trap (Demo and editable Pen). The focus will stay within the modal window as long as it is active.

A short video which illustrates good focus management.

If you compare the first and the last Pen you will see there isn’t a lot of extra code. It’s probably not perfect, but the final solution is much nicer to use.

There is another example for an accessible modal and a great article called Using tabindex by people from Google.
If you want to learn more about keyboard testing visit the WebAIM website. They provide a list „of the most common online interactions, the standard keystrokes for the interaction, and additional information on things to consider during testing.“ For more examples of focus management, check out the egghead.io video „Focus management using CSS, HTML, and JavaScript“ by Marcy Sutton or the A11ycasts episode „What is Focus?“ by Rob Dodson.

If you need a button, use the <button> element

I already wrote about buttons in the first article, but apparently a lot of people use generic elements as buttons. So, I guess it does no harm to write some more about that topic.

I made a Pen (debug mode / Pen with code) to illustrate some of the issues of using a span or div as a button over a button or input element. If you tab through the page you will experience that you can focus the first button, but not the second one. The reason for this is – of course – that the first button is a button and the second one a div. You can work around that issue by adding tabindex="0" to the div, which makes an initially non-focusable element focusable. That's why the third and fourth button are focusable even though they're divs.

// Button and focusable
<button class="btn">I'm a button</button>
// Div and not focusable
<div class="btn">I'm a div</div>
// Still just a div, but focusable
<div class="btn" tabindex="0">I'm a div</div>
// Button role and focusable
<div class="btn" tabindex="0" role="button">I'm a div</div>

The div-button is indeed focusable but still behaves like a div, even if you add a role of button. To illustrate that, I added a simple click event handler to all .btn elements (Pen). If you click the buttons an alert box will pop up, but if you try do the same using keys (Enter or Spacebar), only the first button will trigger an event. You would have to add a key event handler to the div-buttons to fully mimic the default button behavior, which seems like a lot of unnecessary overhead, doesn't it? That's why you should use the <button> element if you need a button.

Watch the A11ycasts episode „Just use button“ by Rob Dodson or read Links, Buttons, Submits, and Divs, Oh Hell by Adrian Roselli for more details and examples.

Screen reader users must be informed when content changes dynamically

Usually, screen readers only announce content when an element is focused or the user uses his/her screen reader’s own navigation commands. If content is loaded dynamically and inserted into the DOM, only sighted users will be aware of the changes. ARIA Live Regions provide several options to work around that issue. I’ll show you how in an example.
Let’s say you have a profile settings page where you’re able to edit personal data and save it. When the save button is clicked changes are saved without reloading the page. An alert informs the user whether the changes where successful or not. This may happen immediately or take some time. I recorded a quick video to show you what I just explained.

A video illustrating ARIA Live regions

You can see that the action was successful, but you can’t hear it. Screen reader users won’t notice the change, but there’s a simple solution for this issue. By adding a role of status or alert to the message box screen readers will listen for content updates in that element.

<div class="message" role="status">Changes saved!</div>

If the text of the message changes the new text will be read out. You can see and hear that in action in this video and take a look at the code in this Pen.

Be polite to your users

The difference between status and alert is that an alert will interrupt the screen reader if it's in the course of announcing something else. status will wait until the screen reader has finished announcing.

There’s another attribute called aria-live, which can take three possible values off, polite or assertive. off is the default value, aria-live="polite" is equivalent to role="status" and aria-live="assertive" to role="alert". In some “well-known predefined cases it is better to use a specific provided live region role. Also if a browser doesn't support role you may want to try using both attributes. Léonie Watson shared some test results in „Screen reader support for ARIA live regions“.

<div role="alert" aria-live="assertive"></div>

Sometimes it makes sense to announce more than just the content that has changed

By default screen readers only present content that has changed, even if there is other content within the same live region, but it occasionally makes sense to announce the whole text.
It’s possible to change the default behaviour with the aria-atomic attribute. If you set it to true, assistive technologies will present the entire contents of the element.

There is an aria-atomic test case demo by Paul J. Adam that compares different live region settings. He also tested his demo with VoiceOver on iOS 8.1 and recorded it so you can see it in action. I suggest you watch the recording (VoiceOver iOS 8.1 Speaking Characters Remaining aria-atomic & aria-relevant on aria-live regions) if you want to better understand possible use cases for aria-atomic.

Some things to consider

  • Live Regions do not move focus, they just trigger announcement of text
  • Use alert only for critical changes. status is better in most cases, because it's politer.
  • Avoid designing alerts that disappear automatically because they may disappear too quickly
  • During my tests, I had issues with VoiceOver. Hiding the alert using CSS or creating it dynamically didn’t work all the time. Make sure you test your Live Regions thoroughly in different browsers with different software.

Of course, there’s an A11ycasts episode „Alerts!“ by Rob Dodson for more details and examples. Heydon Pickering has another example for live regions in his collection of ARIA examples.

You don’t have to guess which usage patterns your widgets must provide

It’s often hard to think of all the features a widget must provide in terms of navigation and accessibility. Gladly there’s a resource called WAI-ARIA Authoring Practices 1.1 that helps us with that. „WAI-ARIA Authoring Practices is a guide to understanding how to use WAI-ARIA to create an accessible Rich Internet Application. It describes recommended WAI-ARIA usage patterns and provides an introduction to the concepts behind them.“

They have guides for building accordions, sliders, tabs, and more.

Accessible JavaScript components

There are also great resources with accessible JavaScript components.

If you know additional resources please share them in the comments.

Recap

Leverage the advantages of JavaScript to improve your site’s accessibility. Take care of focus management, inform yourself about common usage patterns and consider screen reader users when you manipulate the DOM. Above all don’t forget who you are making websites for and have fun while you’re at it.

Going beyond

That’s it for now. I hope that these tips will help you write more accessible HTML. A big thanks to Heydon Pickering, because his book „Inclusive Front-End Design Patterns” built the foundation of most of the stuff that you’ve just read. If you want to learn more about accessibility and inclusive design I highly suggest you read his book.

More accessibility tips

This article is the second one in a series of four. The others are in the works and soon to be released.

  1. Writing HTML with accessibility in mind
  2. Writing JavaScript with accessibility in mind
  3. Writing CSS with accessibility in mind
  4. Up next: Learn how to design and develop with accessibility in mind

Thank you for reading and please don’t forget to like and share this article if you enjoyed it.

Special thanks to Adrian Roselli for helping me with this article and Eva for proofreading my writing.

While I work on the next post, you can check out some other stuff I wrote:

Resources

--

--

Manuel Matuzovic

Frontend Developer / @wearewebclerks meetup organizer / slavic studies student / @mmatuzo on Twitter