Use accessible modal windows instead of pop-ups

Technology oriented Frontend developer

Modal windows should be used instead of pop-up windows, and should be made accessible with WAI-ARIA. In a modal dialog screen-readers will speak the title, the text, and the currently focused button automatically. In the following example the title is called “modalTitle” and the text is called “modalDescription”.

The first line declares a container that encompasses the whole dialog. HTML5 still does not have a proper dialog element that is supported everywhere. Therefore use the WAI-ARIA role "dialog".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<main id="mainPage" role="main"
      aria-hidden="true">
    <div id="modal"
         role="dialog"
         aria-labelledby="modalTitle"
         aria-describedby="modalDescription"
         aria-hidden="false">
        <div id="modalDescription" class="screen-reader-offscreen">
            Beginning of modal dialog window example. Escape will cancel and close the window.
        </div>
        <h1 id="modalTitle">Modal dialog window example</h1>
        <p>
            These are the onscreen instructions that are not attached explicitly to a focusable element.
            Can screen reader users read this text with the virtual cursor?
        </p>
        <button id="modalCloseButton" title="Close modal dialog window">
            <img id="cancel" src="x.png" alt="Close modal dialog window">
        </button>
    </div>
</main>
16

The modalCloseButton is the only button and the first focusable element in the dialog. It is therefore the best place to set initial keyboard focus (as in: I can just press “return” and carry on with my task). Make sure each active dialog has a focused descendant element that has keyboard focus. When dialog is closed, you must also set focus back to the element that opened the dialog, or any other useful element from which the user of your app will most likely continue working.

<main id="mainPage" role="main"
      aria-hidden="true">
    <div id="modal"
         role="dialog"
         aria-labelledby="modalTitle"
         aria-describedby="modalDescription"
         aria-hidden="false">
        <div id="modalDescription" class="screen-reader-offscreen">
            Beginning of modal dialog window example. Escape will cancel and close the window.
        </div>
        <h1 id="modalTitle">Modal dialog window example</h1>
        <p>
            These are the onscreen instructions that are not attached explicitly to a focusable element.
            Can screen reader users read this text with the virtual cursor?
        </p>
        <button id="modalCloseButton" title="Close modal dialog window">
            <img id="cancel" src="x.png" alt="Close modal dialog window">
        </button>
    </div>
</main>

Remember that WAI-ARIA merely provides semantic information. It does not automatically introduce certain types of behaviour. You have to use JavaScript to do that. To ensure accessibility remember the following:

  • Set focus on the first keyboard focusable element within the dialog
  • Trap keyboard focus and create a natural tab order inside the dialog
  • Provide an escape route
  • Restore focus after closing the dialog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function showModal(dialog) {

    // save current focus
    focusedElementBeforeModal = document.activeElement;

    // Focuses the close button
    dialog.find('button:last-of-type').focus()

    document.getElementById('mainPage').setAttribute('aria-hidden','true');
    document.getElementById('modal').setAttribute('aria-hidden','false');
}

function hideModal() {

    // Moves focus back on closing the dialog
    focusedElementBeforeModal.focus();

    document.getElementById('mainPage').setAttribute('aria-hidden','false');
    document.getElementById('modal').setAttribute('aria-hidden','true');
}
function showModal(dialog) {

    // save current focus
    focusedElementBeforeModal = document.activeElement;

    // Focuses the close button
    dialog.find('button:last-of-type').focus()

    document.getElementById('mainPage').setAttribute('aria-hidden','true');
    document.getElementById('modal').setAttribute('aria-hidden','false');
}

function hideModal() {

    // Moves focus back on closing the dialog
    focusedElementBeforeModal.focus();

    document.getElementById('mainPage').setAttribute('aria-hidden','false');
    document.getElementById('modal').setAttribute('aria-hidden','true');
}

Play with this example of extremely accessible modal dialog in Codepen.

For more information on how to implement accessible modal dialogs and more complex examples read Marco Zehes article Advanced ARIA Tip #2: Accessible modal dialogs and/or look at an example by Greg Kraus called The Incredible Accessible Modal Window, also available on GitHub.