Modals

Modals (also know as dialogs) can require a lot of work to be accessible. However, there is a new element dialog which takes care of a lot of these issues, but it is not 100% backwards compatible.

Can I Use - dialog support statistics

An example dialog

An example dialog

This is an alertdialog (in 'modal' mode) using the dialog element.

Because it is in 'modal' mode, you are able to close it by pressing the ESC key or by pressing the 'Close dialog' button.

Modals must be accessible for both 1 keyboard users and 2 screen-reader users.

1 Keyboard users

The modal should be opened and closed with a keyboard and have focus (technically, :focus-visible) states for any button that opens/closes the modal.

After closing the modal, the focus should return to the button which opened it - either when the user presses ESC or clicks the close button.

When the modal is open, the rest of the page should not be accessible via a keyboard i.e. it should have a focus trap.

Focus traps explained

To achieve a focus trap, it can be marked as either as inert or all interactive elements can be marked with tabIndex="-1" or a focus trap could be used to capture TAB key events and prevent the user from tabbing to elements outside of the modal.

The user should be able to press ESC to close the modal.

2 Screen-reader users

The modal should inform the user when it opens that it is a modal/dialog and the user’s focus should be taken to the modal upon opening.

The rest of the page (i.e. the content 'underneath' the modal) should not be accessible to a screen-reader. It can be marked as either aria-hidden="true" or inert.

See Hiding elements accessibly for further information.

General UX (user experience)

The user should be able to click outside of the modal e.g. on the background to close the modal. Although this is not techncially an accessibility requirement.

_Note:_ If the user clicks into the background of the app to close the modal, focus does not have to return to the opening button and can return to `body`.

Note: The dialog element does not close itself when the user clicks outside of it.

Dialog element code example

The following code example shows a dialog element which is automatically shown after 500 milliseconds.

<div aria-labelledby="dialog-title" id="dialog">
  <h2 id="dialog-title">An alert modal</h2>
  <p>Some generic copy.</p>
  <button type="button" onClick="javascript:closeDialog()">Close</button>
</div>
<script>
  // Use JavaScript to show the modal dialog on first page load

  /** @var {HTMLElement | null} */
  const dialog = document.querySelector(".dialog");

  /** @var {number} */
  const DIALOG_DELAY_IN_MS = 500;

  // Show dialog after N seconds
  setTimeout(() => {
    dialog.showModal();
  }, DIALOG_DELAY_IN_MS);

  const closeDialog = () => {
    dialog?.close();
  };
</script>

Further reading:

  1. Mozilla dialog element definition
  2. W3C WAI accessible modal example
  3. Focus trapping for accessibility
  4. Introducing inert - Chrome developers blog
  5. Dialog focus in screen-readers
  6. Can I Use - dialog support statistics

Want to work with us?

Let’s talk about your project