Creating Accessible Dialogs
Dialogs, Modals or Popups. I think almost every web developer must have implemented something like this at least once. But have you ever stopped to think what the UI pattern would be like to people using screen readers?
In this blog I aim to explain how you can make your dialog accessible and what that even means, by using interactive examples.
What is an accessible dialog?
Let's start by giving a bad example, and then we will improve it. The following example is not accessible. I'm sure you've come across this kind of dialog before, or have even implemented something like this yourself.
<div class="dialog-backdrop"> <div class="dialog-content"> <h2>This dialog is not accessible</h2> </div> </div>
There are a few problems with this dialog:
- The dialog does not tell accessibility tools that it is a dialog. This means that when it is opened a screen reader will not announce that a dialog has been opened. And thus will continue to read the rest of the content.
- The focus is not trapped inside the dialog. When you press tab it will continue to the next element on the page even though the dialog is still open.
- It is not possible to close the dialog with the escape key.
We can see from the accessibility tree that the dialog is just seen as generic content. This means that a user that is using a screen reader might not even be able to interact with the dialog.
The above example is a representation of the accessibility tree that you can see in Chrome DevTools. This is a relatively new functionality introduced in Chrome DevTools. It is similair to the DOM tree but only contains accessibility metadata instead of html elements. Learn how to open it here.
How can we improve this?
Supporting all the accessibility features that a dialog needs used to be very complicated. Since the introduction of the
<dialog>
element, this is no longer the case. This element support a number of features that we will need, like a
stylable backdrop, keyboard navigation and a focus trap.
Let's start by defining the dialog.
<dialog class="dialog"> <h2>This dialog is accessible</h2> </dialog>
We can control the open state using javascript.
const element = document.querySelector('.dialog'); element.showModal(); // to open the dialog element.close(); // to close the dialog
You can find more documentation about the <dialog>
element on
the MDN docs.
Let's see what the accessibility tree looks like now. You can also see this yourself by opening devtools and activating the accessibility tree.
You will immediately notice that the tree only contains the dialog. All other content, like the open button, is hidden from the screen reader.
How does it sound?
If you listen to the audio after the beep it says "Close dialog, and 4 more items, dialogue, Close dialog, button". This is what it reads when the dialog is opened. The first thing it mentions is the close button that is automatically selected. While that is needed for a good accessible experience, it's not the first thing we want to hear about this dialog.
To fix this we can define the label of the dialog. There are two ways to do it.
<dialog aria-label="Dialog title"> <h2>Dialog title</h2> </dialog> or <dialog aria-labelledby="dialog-title"> <h2 id="dialog-title">Dialog title</h2> </dialog>
The accessibility tree now shows that the dialog has a label. Try the screen reader button below to hear what this would sound like using a screen reader.
Conclusion
I hope you now have a better idea what it is like to experience a dialog as a screen reader user. Of course this doesn't only apply to dialogs as the methods in the blog can be applied to anything on the web.
Thank you for reading. If you have any questions or suggestions please send me a message on bluesky.