Metadata
Title
✎ Technique: Accessible modal dialogs
Category
general
UUID
ac458e517a0741e3802116e7a726b855
Source URL
https://accessibility.huit.harvard.edu/technique-accessible-modal-dialogs
Parent URL
https://accessibility.huit.harvard.edu/keyboard
Crawl Time
2026-03-23T03:13:08+00:00
Rendered Raw Markdown
# ✎ Technique: Accessible modal dialogs

**Source**: https://accessibility.huit.harvard.edu/technique-accessible-modal-dialogs
**Parent**: https://accessibility.huit.harvard.edu/keyboard

Modal dialogs can enhance usability by focusing attention on a specific message that requires a user action to continue.

An accessible modal dialog is one where keyboard focus is managed properly, and the correct information is exposed to screen readers. HTML and WAI-ARIA can be used to provide the necessary semantic information, CSS the appearance and Javascript the behavior.

## Example

In this modal dialog example, we’ll look at the HTML, CSS and JavaScript separately.

### HTML

The dialog itself must be constructed from a combination of HTML and WAI-ARIA attributes, as in this example:

`<div id="dialog" role="dialog" aria-labelledby="title" aria-describedby="description">`\
`<h1 id="title">Title of the dialog</h1>`\
`<p id="description">Information provided by the dialog.</p>`\
`<button id="close" aria-label="close">×</button>`\
`</div>`

Note the `dialog` role, which tells assistive technologies that the element is a dialog. The `aria-labelledby` and `aria-describedby` attributes are “relationship” attributes that connect the dialog to its title and description explicitly. So when focus is moved to the dialog or inside it, the text within those two elements will be read in succession. The close button has an `aria-label` attribute that overrides the element’s text character of “times” to read “close” when screen readers interact with it.

### CSS

As well as some CSS for color and positioning, the dialog is set to `display:none` by default. When the custom attribute `open` is added to the dialog with JavaScript, the dialog is revealed.

`[role="dialog"][data-open] {`\
`display: block;`\
`}`

Distinctive focus styles are added for the dialog’s the opening and closing buttons so that it’s clear to keyboard users which element is focused. This style is paired with the `hover` style so that keyboard and mouse operation look consistent.

`button:focus, button:hover  {`\
`outline: 3px solid #d4aa00;`\
`}`

### JavaScript

When the “trigger” button is pressed, the script runs the `openDialog()` function:

`function openDialog() {`\
`dialog.setAttribute('data-open', '');`\
`close.focus();`\
`close.addEventListener('keydown', function(e) {`\
`if (e.keyCode == 9) {`\
`e.preventDefault();`\
`}`\
`});`\
`document.getElementById('cover').style.display = 'block';`\
`document.addEventListener('keydown', addESC);`\
`}`

First, `dialog.setAttribute('data-open', '')` adds the `open` attribute to the dialog, which sets the dialog’s CSS display value to `block`. Next, focus is moved to the dialog’s close button. This does two things: It triggers the announcement of the dialog's title and description in screen readers, and it makes the dialog easy to close at the press of a key.

The next block confines focus to the close button, making sure the user does not accidentally leave the dialog until it has been dismissed. That is, if the TAB key is pressed—which would move focus away from the dialog—the default behavior is suppressed with `e.preventDefault();`.

Note the line with "addESC" at the end. That adds a listener for the ESC key so that when it is pressed, `closeDialog()` is run. It is conventional to be able to close a dialog with the ESC key.

`var addESC = function(e) {`\
`if (e.keyCode == 27) {`\
`closeDialog();`\
`}`\
`}`

Clicking or pressing ENTER on the close button will also fire `closeDialog()`:

`function closeDialog() {`\
`dialog.removeAttribute('data-open');`\
`trigger.focus();`\
`document.getElementById('cover').style.display = 'none';`\
`document.removeEventListener('keydown', addESC);`\
`}`

Note the `trigger.focus()` line that moves focus back to whichever element opened the dialog. This is important: Keyboard users should always be returned to where they were before they opened the dialog. If you don't do that, when the close button is hidden (and no longer focusable) the `<body>` element will be focused by default. That will force keyboard users to step through the page manually to find the spot where they left off.

## Code editor

[Try operating the dialog with only your keyboard in the code editor provided (external link)](https://codepen.io/team/hwpdas/pen/dyYVjZr). See how the keyboard operation is affected when you remove the JavaScript lines that manage focus!

See also:

- [Techniques](https://accessibility.huit.harvard.edu/page-categories/techniques)
- [Alerts](https://accessibility.huit.harvard.edu/accessibility-topics/alerts)
- [Focus](https://accessibility.huit.harvard.edu/accessibility-topics/focus)
- [Screen reader](https://accessibility.huit.harvard.edu/access-technologies/screen-reader)
- [Keyboard](https://accessibility.huit.harvard.edu/access-technologies/keyboard)
- [Speech recognition](https://accessibility.huit.harvard.edu/access-technologies/speech-recognition)
- [Switch-based input](https://accessibility.huit.harvard.edu/access-technologies/switch-based-output)
- [Custom widgets and controls ✎](https://accessibility.huit.harvard.edu/content/custom-widgets-and-controls)
- [Keyboard ✎](https://accessibility.huit.harvard.edu/content/keyboard)
- [Provide name, role, and value information ✎](https://accessibility.huit.harvard.edu/content/provide-name-role-and-value-information)
- [Support keyboard interaction ✎](https://accessibility.huit.harvard.edu/content/support-keyboard-interaction)
- [Use accessible design patterns ✎](https://accessibility.huit.harvard.edu/content/use-accessible-design-patterns)
- [Operable](https://accessibility.huit.harvard.edu/techniques/principles/operable)
- [Perceivable](https://accessibility.huit.harvard.edu/principles/perceivable)
- [Robust](https://accessibility.huit.harvard.edu/principles/robust)
- [Blind](https://accessibility.huit.harvard.edu/disabilities/blind)
- [Low vision](https://accessibility.huit.harvard.edu/disabilities/low-vision)
- [Motor impairment](https://accessibility.huit.harvard.edu/disabilities/motor-impairment)
- [CSS](https://accessibility.huit.harvard.edu/web-technologies/css)
- [HTML](https://accessibility.huit.harvard.edu/web-technologies/html)
- [JavaScript](https://accessibility.huit.harvard.edu/web-technologies/javascript)