Writing JavaScript with Accessibility in Mind

    Manuel Matuzovic

    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.

    This article was originally published on Medium.

    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

    JavaScript Accessibility

    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 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 his article JavaScript is not an enemy of accessibility! I highly suggest you read his post.

    But enough with the introductory talk! Let’s get to it …

    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 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 programatically focusable (e.g. with JavaScript), 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 this screen recording.

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

    <div class="modal" id="modal2" tabindex="0">
    function showModal() {
      var modal = document.getElementById('modal2');

    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.

    We can use document.activeElement to get the current element in focus.

    var lastFocusedElement;
    function showModal() {
      lastFocusedElement = document.activeElement;
      var modal = document.getElementById(modalID);

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

    function removeModal() {

    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 advisable 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, as can be seen in this screen recording.

    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 of 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 <div>s.

    <!-- 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 their 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 provides 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 were successful or not. This may happen immediately or take some time. I recorded a quick video to show you what I just explained.

    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. In contrast, 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. Of the three, off is the default value, aria-live="polite" is equivalent to role="status" and aria-live="assertive" the equivalent 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 behavior 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 several great resources for accessible JavaScript components out there:

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


    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 and JavaScript. A big thanks to Heydon Pickering, because his book Inclusive Front-End Design Patterns is 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.

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


    This is a list of all the resources linked to in this article.