Dialog
Modal dialog using the native HTML <dialog> element. No JavaScript dependencies required.
Basic dialog
Section titled “Basic dialog”<dialog class="af-dialog" id="my-dialog">
<div class="af-dialog-header">
<h2 class="af-dialog-title">
Confirm action
</h2>
<button class="af-btn af-btn-icon" aria-label="Close"
onclick="this.closest('dialog').close()">
×
</button>
</div>
<div class="af-dialog-body">
<p>
Are you sure you want to continue? This action cannot be undone.
</p>
</div>
<div class="af-dialog-footer">
<button class="af-btn af-is-secondary"
onclick="this.closest('dialog').close()">
Cancel
</button>
<button class="af-btn af-is-danger"
onclick="this.closest('dialog').close()">
Delete
</button>
</div>
</dialog>
<button class="af-btn"
onclick="document.getElementById('my-dialog').showModal()">
Open Dialog
</button>Preview
Section titled “Preview”Why native <dialog>?
Section titled “Why native <dialog>?”showModal()marks the rest of the page as inert.- ESC key closes the dialog automatically.
- Body scroll lock while the modal is open.
::backdroppseudo-element. No extra markup for the overlay.
Open with showModal(). Close with close().
const dialog = document.getElementById('my-dialog');
dialog.showModal();
dialog.close();
if (dialog.open) {/* dialog is visible */}| Class | Purpose |
|---|---|
af-dialog | The <dialog> element itself |
af-dialog-header | Header row. Flexbox, space-between. |
af-dialog-title | Title text inside the header |
af-dialog-body | Main content area |
af-dialog-footer | Footer row. Flexbox, end-aligned. |
Dialog with form
Section titled “Dialog with form”<dialog class="af-dialog" id="form-dialog">
<form method="dialog">
<div class="af-dialog-header">
<h2 class="af-dialog-title">
Edit profile
</h2>
<button class="af-btn af-btn-icon" aria-label="Close"
formmethod="dialog">
×
</button>
</div>
<div class="af-dialog-body">
<div class="af-stack af-gap-md">
<div class="af-field">
<label for="name" class="af-label">
Name
</label>
<input id="name" class="af-input" type="text" value="Iain Todd">
</div>
<div class="af-field">
<label for="email" class="af-label">
Email
</label>
<input id="email" class="af-input" type="email" value="iain@example.com">
</div>
</div>
</div>
<div class="af-dialog-footer">
<button class="af-btn af-is-secondary" formmethod="dialog">
Cancel
</button>
<button class="af-btn">
Save
</button>
</div>
</form>
</dialog>
<button class="af-btn"
onclick="document.getElementById('form-dialog').showModal()">
Edit Profile
</button>Using <form method="dialog"> lets any submit button close the dialog automatically.
Closing on backdrop click
Section titled “Closing on backdrop click”The native <dialog> doesn’t close on backdrop click by default. Add this if you want it:
dialog.addEventListener('click', (e) => {
if (e.target === dialog) dialog.close();
});Accessibility
Section titled “Accessibility”- Use
<dialog>element. Not a<div>withrole="dialog". - Provide a visible title via
af-dialog-title. - Add
aria-labeloraria-labelledbyif the title is not visible. - Close buttons need
aria-label="Close".