Technique H102:Creating modal dialogs with the HTML dialog
element
About this Technique
This technique relates to 2.4.3: Focus Order (Sufficient when used for changing a Web page dynamically).
This technique applies to HTML.
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">×</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 dialog
s), and showModal()
(for modal dialog
s) - 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);
});
Related Resources
No endorsement implied.
Tests
Procedure
- Find the components on the page that invoke modal
dialog
elements. - Check that each
dialog
can be opened using the keyboard to activate the invoking element (for example, activate abutton
by pressing the Enter key or Spacebar. - When the modal
dialog
is opened, check that focus has moved to it / one of its focusable descendants. - While the modal
dialog
is open, check that keyboard focus cannot move to elements of the primary document. - 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.