Skip to content

Technique H102:Creating modal dialogs with the HTML dialog element

Applicability

HTML

This technique relates to 2.4.3: Focus Order (Sufficient when used with Changing a Web page dynamically using one of the following techniques:).

Description

Website authors often use modal dialogs to focus a user's attention on information, or a task-related activity beyond the scope of the primary page's content. Modal dialogs can be built in markup using ARIA's dialog role and related attributes, or the HTML's dialog element. As well as meeting the first rule of ARIA, the HTML dialog element offers several advantages to its ARIA counterpart, with the browser handling these features:

  • keyboard focus is moved to the newly-opened modal dialog;
  • keyboard focus returns to the invoking element (assuming the element is still on the page) when the modal dialog is closed;
  • keyboard focus is limited to the contents of the modal dialog and the browser's chrome (e.g., the browser-specific UI, such as the address bar, etc.);
  • the page's content 'outside' of the modal dialog becomes inert, resulting in the content becoming hidden from assistive technologies, and inoperable to all users, so long as the modal dialog remains open;
  • the use of the Escape key to close the modal dialog.

This technique uses the HTML dialog element rather than a custom ARIA implementation, reducing the level of effort to create an accessible modal dialog.

Examples

Example 1: A dialog to sign up to a mailing list

This is an example of using a modal dialog element to show a mailing-list sign-up form to a user. The main part of the page contains a button element that, when activated, invokes the modal dialog. The button uses the type attribute to tell the browser that this isn't a submit button.

When the modal dialog is opened, the browser will treat all content outside of the modal dialog as inert, rendering it inoperable and hiding the content from assistive technology. For example, a screen reader will not be able to reach or announce any of the inert content. Additionally, because the page content is inert, keyboard focus will only be able to reach focusable elements within the dialog element, and the browser's controls. When invoked, the browser automatically sets focus to the first focusable element in the dialog's DOM. In this example the h1 element will receive focus because it has a tabindex="-1" attribute. Note that, although the dialog's close button is visibly before the h1, it is the last item in the dialog's DOM. If the button was first, it would receive focus when dialog was opened.

The HTML

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,
     initial-scale=1, shrink-to-fit=no">
    <title>Turbo Encabulator News</title>
  </head>
  <body>
    <main>
      <h1>All The News About Turbo Encabulators</h1>
      <button class="open-modal" type="button">Sign up to our mailing list!</button>
    </main>
    <dialog aria-labelledby="dialog-heading" id="mailing-list-dialog">
      <h1 id="dialog-heading" tabindex="-1">Sign up to our mailing list</h1>
      <form>
        <p class="req-note">All form fields are required.</p>
        <div>
          <label for="fname">First Name</label>
          <input aria-required="true" autocomplete="given-name" id="fname" type="text">
        </div>
        <div>
          <label for="lname">Last Name</label>
          <input aria-required="true" autocomplete="family-name" id="lname" type="text">
        </div>
        <div>
          <label for="email">Email address</label>
          <input aria-required="true" autocomplete="email" id="email" type="text">
        </div>
        <button class="sign-up" type="submit">Sign up</button>
      </form>
     <form method="dialog">
        <button aria-label="close" class="close-modal">&times;</button>
      </form>
    </dialog>
  </body>
</html>

The CSS

*, *::after, *::before {
  box-sizing: inherit;
}

body {
  background:#fff;
  color:#000;
  font:1rem/1.5 system-ui, Helvetica, Roboto, sans-serif;
}

*:focus-visible {
  outline:1px solid #0054AE;
  outline-offset:1px;
}

dialog {
  border:1px solid #000;
  padding:2rem;
  position:relative;
}
 
dialog::backdrop {
  background-color:hsla(0, 0%, 0%, .5);
}
 
.close-modal {
  inset-block-start:1.5rem;  
  inset-inline-end:1.5rem;  
  line-height:1.3;
  padding:0.25em 0.5em;
  position:absolute;
}

.sign-up {
  background:#000;
  color:#fff;
  padding:0.25em;
}

dialog h1 {
  display:inline-block;
  line-height:1.3333;
  margin:0;
  max-inline-size:95%;
}

form {
  display:grid;
  grid-gap:20px;
  grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));
}

.req-note, .sign-up {
  grid-column:1 / -1;
}
 
label {
  display:block;
}
 
input {
  border:1px solid hsl(0, 0%, 50%);
  font:inherit;
  inline-size:calc(100% - 4px);
}

button {
  background:#fff;
  border:1px solid hsl(0, 0%, 50%);
  border-radius:3px;
  color:inherit;
  font:inherit;
  margin:0;
}

The JavaScript

The script is necessary to display the dialog when invoked. The HTML dialog element can be opened using two different commands: show() (for non-modal dialogs), and showModal() (for modal dialogs) - used in this example.

Note: instead of writing a function to close the dialog, the close button is nested within a separate form element with a method="dialog" attribute. This method allows the dialog to be closed when activating this button, and the browser will handle returning keyboard focus to the invoking element,

document.addEventListener("DOMContentLoaded", function(e){
  const d = document.querySelector("dialog");
  const btnOpen = document.querySelector(".open-modal");

  btnOpen.addEventListener("click", function(){
    d.showModal();
  }, false);

});

Other sources

No endorsement implied.

Tests

Procedure

  1. Find the components on the page that invoke modal dialog elements.
  2. Check that each dialog can be opened using the keyboard to activate the invoking element (for example, activate a button by pressing the Enter key or Spacebar.
  3. When the modal dialog is opened, check that focus has moved to it / one of its focusable descendants.
  4. While the modal dialog is open, check that keyboard focus cannot move to elements of the primary document.
  5. When the modal dialog is closed, check that focus is placed back onto the invoking element, if the element still exists on the page.

Expected Results

  • Checks #2, #3, #4 and #5 are true.
Back to Top