Accessible Modal Windows
Posted on May 25, 2016
Love them or hate them, modal windows are an established pattern employed by nearly every website today. It is true that they are easier to abuse than the office candy jar. For example, do you want to block a user from finishing a task to show an interstitial ad? Use a modal! Need to make your website a little more app-like just because? Use a modal! Desperate to go viral? Use a… well, you get the point. But for all their misuse, modals do have legitimate utility.
There are a variety of reasons why we would opt to use modal windows, and for the sake of controversy, we can discuss in another post. What they all share in common is that they are excellent for contextualizing a subtask while retaining the user within their current place on the page. When triggered, the modal window appears, usually accompanied by a darker or lighter backdrop beneath it to highlight its content front and center for immediate interaction. But how do we achieve this effect—which is overly visual—in an accessible way?
Modal windows will require some special considerations in order to make their content available to assistive technologies like screen readers or alternative inputs like keyboard navigation. For getting users to interact with modal content, or to simply dismiss it, how will they find it when a modal’s content is most likely in a different part of the DOM, separate from its trigger? How will they close it? And what happens afterwards?
Let’s take a look at various ways to go about addressing these concerns.
ARIA Roles
Using
role="dialog"
In the modal’s root, we can use
aria-labelledby
aria-describedby
<div
class="modal"
role="dialog"
aria-labelledby="modal-labelledby"
aria-describedby="modal-selection-describedby"
>
<h2 id="modal-selection-labelledby">The Great Modal</h2>
<p id="modal-selection-describedby">This modal will do great things.</p>
</div>
I should also point out that this content doesn’t necessarily have to be part of the visual presentation.
We can further separate modal content from the rest of the page using the aria-hidden attribute on anything that is not applicable to an open window. What content would that be? Perhaps the main navigation or footer or even the main content area. However, be very careful in how aria-hidden is applied because it will impact every child element. In other words, if a modal’s markup is situated in the DOM within a block set to aria-hidden, the modal in turn will be hidden from screen readers.
Providing Focus
One thing to remember is that your modal window’s trigger may not be anywhere near the modal window in the DOM structure. When opening a modal, it’s important that its content is actionable and the user is not left to find it wherever it lives in the markup. With a mouse, this is easy. We just move the cursor over top of the window and start clicking. With keyboard navigation or screen readers, we need to use
:focus
When we instantiate a modal window as JavaScript loads successfully, we can assign a tabindex of -1 to each modal window element so that when it is opened, we can programmatically set its
:focus
<div
class="modal"
role="dialog"
aria-labelledby="modal-labelledby"
aria-describedby="modal-selection-describedby"
tabindex="-1"
></div>
Class Dismissed
Not so fast! That was a joke and I apologize. By dismissing, I’m talking about closing the modal window, which is the best thing to do with them, right? As it often goes, a little redundancy can go a long way. One way to close a window would be through using the ESC key. Backdrops can be created with a button element, which will also close the modal. And finally, a modal window may have a more explicit close button in one of the corners, primarily for visual users.
Modal windows should always be a round trip. After closing a modal, we should politely drop off at the orginial point of departure. The way we do that is by capturing the element that triggered the modal upon opening it, and then returning
:focus
On way of capturing the clicked element in the opening function
this.clickedElement = event.currentTarget;
Then in the close function, we return
:focus
this.clickedElement.focus();
Wrapping things up
Modals present a unique challenge for accessibility, and design alternatives should be considered if any complexity is introduced. As we can see, building them correctly isn’t simply a matter of opening and closing them. As with the rest of front-end development, there is much more than meets the eye, or meets the mouse. This is our job.