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.
Key Takeaways
- JavaScript can be used to improve website accessibility, not hinder it. It can make content available to a wider audience, including those with old browsers, slow internet connections, or strict security restrictions.
- Focus management is crucial for website accessibility. Websites should be navigable by keyboard, allowing users to jump from one focusable element to another in the Document Object Model (DOM) order.
- Using the correct HTML elements, such as the
- Screen reader users must be informed when content changes dynamically. This can be achieved using ARIA Live Regions, which allow screen readers to announce content updates.
- Developers don’t have to guess which usage patterns their widgets must provide for accessibility. Resources like the WAI-ARIA Authoring Practices 1.1 guide can provide valuable insights.
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 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">
...
</div>
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.
We can use document.activeElement
to get the current element in focus.
var lastFocusedElement;
function showModal() {
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() {
...
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 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:
- Practical ARIA examples
- Modaal — a WCAG 2.0 Level AA accessible modal window plugin
- Frend — a collection of accessible, modern front-end components
- The A11Y Project patterns
If you know of any 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 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.
Resources
This is a list of all the resources linked to in this article.
- A11ycasts #03 — What is Focus?
- A11ycasts #04 — Controlling focus with tabindex
- A11ycasts #05 — Just use button
- A11ycasts #10 — Alerts!
- Book: Inclusive Front-End Design Patterns
- Don’t Use Tabindex Greater than 0
- Focus management using CSS, HTML, and JavaScript
- Focusable Elements — Browser Compatibility Table
- Links, Buttons, Submits, and Divs, Oh Hell
- MDN: HTMLElement.focus()
- MDN: tabindex
- MDN: Keyboard-navigable JavaScript widgets
- The Incredible Accessible Modal Window
- Using tabindex
- WebAIM Keyboard Testing
- WebAIM Keyboard Accessibility
- WAI-ARIA aria-atomic
Frequently Asked Questions about Writing JavaScript with Accessibility in Mind
What is the importance of writing JavaScript with accessibility in mind?
Writing JavaScript with accessibility in mind is crucial because it ensures that your website or application is usable by all individuals, including those with disabilities. This not only broadens your user base but also enhances user experience and satisfaction. It’s also important for legal compliance in many regions, as accessibility is a requirement under various disability discrimination acts.
How can I make my JavaScript code more accessible?
There are several ways to make your JavaScript code more accessible. Firstly, ensure that your website or application is keyboard-friendly. This means that users should be able to navigate your site using only the keyboard. Secondly, make sure that your site is easily navigable with a screen reader. This can be achieved by using semantic HTML and ARIA roles. Lastly, always provide alternative text for images and ensure that your site has sufficient color contrast.
What is ARIA and how does it improve accessibility?
ARIA stands for Accessible Rich Internet Applications. It’s a set of attributes that define ways to make web content and web applications more accessible to people with disabilities. ARIA helps with dynamic content and advanced user interface controls developed with Ajax, HTML, JavaScript, and related technologies. It can improve accessibility by providing additional information about elements, their role, and their current state.
How does keyboard navigation enhance accessibility?
Keyboard navigation is essential for users who cannot use a mouse or a touch screen. By ensuring that all functionalities of your website or application can be accessed using the keyboard alone, you make your site more accessible to users with motor disabilities or visual impairments. This can be achieved by using tabindex and focus management in your JavaScript code.
What is the role of semantic HTML in accessibility?
Semantic HTML refers to the use of HTML markup to reinforce the semantics or meaning of the content. For example, using the
How can I ensure sufficient color contrast for accessibility?
Sufficient color contrast is important for users with visual impairments. You can ensure this by choosing color combinations that meet the WCAG 2.1 guidelines for contrast ratio. There are online tools available that can help you check the contrast ratio of your chosen colors.
What is the importance of providing alternative text for images?
Providing alternative text for images is crucial for visually impaired users who rely on screen readers. The alternative text should accurately describe the image content so that users who cannot see the image can still understand its purpose in the context of the page.
How can I test the accessibility of my JavaScript code?
There are several tools available for testing the accessibility of your JavaScript code. These include automated testing tools like aXe and Lighthouse, as well as manual testing using a screen reader and keyboard-only navigation. It’s important to use a combination of automated and manual testing to ensure comprehensive accessibility.
What are some common accessibility issues in JavaScript?
Some common accessibility issues in JavaScript include lack of keyboard accessibility, insufficient color contrast, missing alternative text for images, and lack of ARIA roles or incorrect use of ARIA roles. These issues can make your site difficult or impossible to use for individuals with disabilities.
How can I learn more about JavaScript and accessibility?
There are many resources available for learning more about JavaScript and accessibility. These include online tutorials, courses, and documentation from organizations like the W3C. Additionally, practicing writing accessible code and regularly testing your code for accessibility can greatly enhance your understanding and skills.
Frontend Developer / @wearewebclerks meetup organizer / slavic studies student