Dialog Element
The <dialog> element provides a native way to create modal and non-modal dialogs with built-in accessibility features.
The Old Way
Section titled “The Old Way”<div class="modal-overlay" id="overlay" onclick="closeModal()"> <div class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title"> <button class="close-btn" onclick="closeModal()" aria-label="Close">×</button> <h2 id="modal-title">Confirm Action</h2> <p>Are you sure you want to proceed?</p> <button onclick="confirm()">Yes</button> <button onclick="closeModal()">No</button> </div></div>
<style>.modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); z-index: 1000;}.modal-overlay.open { display: flex; justify-content: center; align-items: center; }.modal { background: white; padding: 2rem; border-radius: 8px; }</style>
<script>let previouslyFocused;
function openModal() { previouslyFocused = document.activeElement; document.getElementById('overlay').classList.add('open'); document.body.style.overflow = 'hidden'; trapFocus();}
function closeModal() { document.getElementById('overlay').classList.remove('open'); document.body.style.overflow = ''; previouslyFocused?.focus();}
function trapFocus() { const modal = document.querySelector('.modal'); const focusable = modal.querySelectorAll('button, [href], input, select, textarea'); const first = focusable[0]; const last = focusable[focusable.length - 1]; first.focus();
modal.addEventListener('keydown', (e) => { if (e.key === 'Tab') { if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } } if (e.key === 'Escape') closeModal(); });}</script>Problems:
- Significant JavaScript for accessibility
- Manual focus trapping required
- Must prevent body scroll manually
- ARIA attributes must be added manually
The Modern Way
Section titled “The Modern Way”<dialog id="confirmDialog"> <h2>Confirm Action</h2> <p>Are you sure you want to proceed?</p> <form method="dialog"> <button value="no">No</button> <button value="yes">Yes</button> </form></dialog>
<button onclick="document.getElementById('confirmDialog').showModal()"> Open Dialog</button>
<script>const dialog = document.getElementById('confirmDialog');dialog.addEventListener('close', () => { console.log('User selected:', dialog.returnValue);});</script>Benefits:
- Built-in focus trapping
- ESC key closes automatically
- Backdrop provided by browser
- Returns focus to trigger element
returnValuecaptures button value
Dialog Methods
Section titled “Dialog Methods”| Method | Description |
|---|---|
show() | Opens as non-modal (no backdrop, page still interactive) |
showModal() | Opens as modal (backdrop, focus trapped) |
close(returnValue) | Closes dialog, optionally sets returnValue |
Styling the Dialog
Section titled “Styling the Dialog”dialog { border: none; border-radius: 8px; padding: 2rem; max-width: 400px;}
/* Style the backdrop */dialog::backdrop { background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(2px);}
/* Animate open/close */dialog[open] { animation: fade-in 0.2s ease-out;}
@keyframes fade-in { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); }}Form Integration
Section titled “Form Integration”Using method="dialog" on a form inside a dialog closes it on submit:
<dialog id="formDialog"> <form method="dialog"> <label for="name">Name</label> <input type="text" id="name" name="name" required> <button type="submit">Save</button> <button type="button" onclick="this.closest('dialog').close()">Cancel</button> </form></dialog>Handling Close Events
Section titled “Handling Close Events”const dialog = document.getElementById('myDialog');
// Fires when dialog closesdialog.addEventListener('close', () => { if (dialog.returnValue === 'confirm') { // User confirmed }});
// Prevent ESC from closing (if needed)dialog.addEventListener('cancel', (e) => { e.preventDefault();});Browser Support
Section titled “Browser Support”Supported in all modern browsers. See caniuse.com/dialog.
Accessibility Considerations
Section titled “Accessibility Considerations”- Automatically receives focus when opened
- Focus is trapped within modal dialog
- ESC key closes the dialog
- Focus returns to triggering element on close
- Announced as dialog to screen readers
- Add
aria-labelledbypointing to dialog heading
<dialog aria-labelledby="dialog-title"> <h2 id="dialog-title">Dialog Heading</h2></dialog>When to Use
Section titled “When to Use”Use <dialog> for:
- Confirmation prompts
- Form modals
- Alert messages
- Any overlay requiring user attention
Consider alternatives for:
- Toast notifications (use ARIA live regions)
- Tooltips (use
titleor custom positioning) - Dropdown menus (use
<details>or Popover API)