dialog elementHTML
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:
dialog;dialog is closed;dialog and the browser's chrome (e.g., the browser-specific UI, such as the address bar, etc.);dialog remains open;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.
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.
<!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>
*, *::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 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);
});
dialog elements.dialog can be opened using the keyboard to activate the invoking element (for example, activate a button by pressing the Enter key or Spacebar.dialog is opened, check that focus has moved to it / one of its focusable descendants.dialog is open, check that keyboard focus cannot move to elements of the primary document.dialog is closed, check that focus is placed back onto the invoking element, if the element still exists on the page.