Purpose
Dialogs present supplemental content, forms, or confirmations in a focused context. Unlike alert dialogs, standard dialogs may contain any content and are not announced immediately by screen readers.
Usage Guidance
- Use dialogs sparingly; they interrupt workflow
- A dialog should have a clear heading and a close mechanism
- Avoid dialogs that contain other dialogs (nested modals)
- Provide a visible close button (
×witharia-label="Close dialog")
Accessibility Considerations
role="dialog"on the containeraria-modal="true"prevents screen readers from navigating outside the dialogaria-labelledbyreferences the dialog’s heading- Trap focus within the dialog while it is open
- On close, return focus to the trigger element
Keyboard Support
| Key | Action |
|---|---|
Tab |
Move focus forward among interactive elements |
Shift+Tab |
Move focus backward among interactive elements |
Escape |
Close the dialog |
Screen Reader Behavior
Screen readers announce the dialog’s label and role when it opens. aria-modal="true" prevents navigation outside the dialog (support varies; use inert on the background as a supplement).
ARIA Requirements
role="dialog"on the containeraria-modal="true"on the containeraria-labelledbypointing to the dialog heading
Common Mistakes
- Not trapping focus (user tabs into background content)
- Not restoring focus to the trigger on close
- Using only Escape to close without a visible close button
- Animating the dialog without respecting
prefers-reduced-motion
Live Example
Accessibility Audit Details
This dialog demonstrates focus trapping, Escape key handling, and focus restoration. Press Escape or the close button to dismiss.
Code Example
<!-- Trigger -->
<button type="button" data-dialog-open="my-dialog">Open Dialog</button>
<!-- Dialog -->
<div
id="my-dialog"
role="dialog"
aria-modal="true"
aria-labelledby="my-dialog-title"
hidden
>
<div class="dialog__inner">
<div class="dialog__header">
<h2 id="my-dialog-title">Dialog Title</h2>
<button
type="button"
aria-label="Close dialog"
data-dialog-close
>✕</button>
</div>
<div class="dialog__body">
<!-- Dialog content -->
</div>
<div class="dialog__footer">
<button type="button" data-dialog-close>Cancel</button>
<button type="submit">Confirm</button>
</div>
</div>
</div>
See main.js for the focus-trapping JavaScript implementation.