Modal/Popup
A modal or popup dialog with minimal JavaScript.
How It Works
This modal is built using the semantic HTML
<dialog>
element with minimal inline
JavaScript. It leverages the native accessibility features of the
dialog element for proper focus management and screen reader
support.
The implementation uses only inline event handlers for minimal JavaScript footprint, making it easy to copy and paste into any project.
Accessibility Features
ARIA Attributes Explained
- aria-haspopup="dialog": Indicates the button opens a dialog popup
- aria-controls="modal": Establishes a relationship between the button and the dialog it controls
- aria-labelledby="modal-title": Associates the dialog with its title, announcing the title when the dialog opens
- aria-describedby="modal-description": Provides additional context about the dialog's purpose
- aria-modal="true": Tells assistive technologies that this is a modal window that blocks interaction with page content
- aria-label="Close modal": Provides an accessible name for buttons that only have icon content
Keyboard Navigation
- Tab key: Moves focus between interactive elements within the dialog
- Escape key: Closes the dialog (built-in behavior of the dialog element)
- Enter/Space: Activates buttons when they have keyboard focus
Focus Management
The <dialog>
element with
showModal()
automatically:
- Traps focus within the dialog when open
- Returns focus to the triggering element when closed
- Makes content outside the dialog inert and unfocusable
What Not To Add
For best accessibility practices, avoid these common mistakes:
-
tabindex="-1" on
<dialog>
: Not needed — the dialog element is already focusable by default - role="alertdialog": Only use this if the modal is urgent (e.g., errors or warnings that require immediate attention)
- role="dialog": Redundant, as the dialog element already has this semantic role built-in
- autofocus attributes: The dialog element handles focus management automatically when using showModal()
Additional Resources
Implementation Code
<!-- Modal trigger button -->
<button
class="modal-trigger"
onclick="document.getElementById('modal').showModal()"
aria-haspopup="dialog"
aria-controls="modal">
Open Modal
</button>
<!-- Modal dialog -->
<dialog
id="modal"
class="modal-dialog"
aria-labelledby="modal-title"
aria-describedby="modal-description"
aria-modal="true"
closedBy="any">
<div class="modal-content">
<h2 id="modal-title">Modal Title</h2>
<p id="modal-description">
This is a modal dialog using the semantic HTML dialog element.
</p>
<button
class="modal-close"
aria-label="Close modal"
onclick="this.closest('dialog').close()">
×
</button>
<div class="modal-actions">
<button
class="modal-button"
aria-label="Close modal"
onclick="this.closest('dialog').close()">
Close
</button>
</div>
</div>
</dialog>