Advanced15 min read

The Dialog Element

Learn how to create native modal and non-modal dialogs using the HTML dialog element, with built-in focus trapping, backdrop styling, and form integration.

The <dialog> Element

The <dialog> element represents a dialog box or popup window. It is hidden by default and can be shown in two modes:

  1. Modal (showModal()) — Overlays the entire page with a backdrop, traps focus inside the dialog, and blocks interaction with the rest of the page. Press Escape to close.
  2. Non-modal (show()) — Opens without a backdrop. The user can still interact with the rest of the page.
html
<dialog id="myDialog">
  <h2>Dialog Title</h2>
  <p>This is a native HTML dialog.</p>
  <button onclick="this.closest('dialog').close()">Close</button>
</dialog>

<button onclick="document.getElementById('myDialog').showModal()">
  Open Modal
</button>

The dialog is a standard HTML element — no JavaScript library needed for modals!

Opening and Closing

Opening

  • dialog.showModal() — Opens as a modal with backdrop and focus trap.
  • dialog.show() — Opens as a non-modal dialog.
  • The open attribute — Adding it directly makes the dialog visible (non-modal), but showModal() is preferred for modals.

Closing

  • dialog.close() — Closes the dialog.
  • dialog.close('result') — Closes and sets dialog.returnValue to the passed string.
  • Pressing Escape closes a modal dialog.
  • A form with method="dialog" inside the dialog closes it on submit.

The close event

js
dialog.addEventListener('close', () => {
  console.log('Return value:', dialog.returnValue);
});

Form method="dialog"

When a form inside a dialog has method="dialog", submitting it closes the dialog. The submit button's value becomes the dialog's returnValue:

html
<dialog id="confirm">
  <form method="dialog">
    <p>Are you sure?</p>
    <button value="yes">Yes</button>
    <button value="no">No</button>
  </form>
</dialog>

Styling with ::backdrop

Modal dialogs create a backdrop pseudo-element that covers the page behind the dialog. You can style it with the ::backdrop pseudo-element:

css
dialog::backdrop {
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
}

The dialog itself can be styled like any element:

css
dialog {
  border: none;
  border-radius: 12px;
  padding: 2rem;
  max-width: 500px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}

Modern browsers handle focus trapping automatically for modal dialogs — focus cannot leave the dialog while it is open, and focus returns to the trigger element when it closes.

Accessibility

The <dialog> element has excellent built-in accessibility:

  • role="dialog" is implicit — screen readers announce it as a dialog.
  • Add aria-label or aria-labelledby to provide an accessible name:
html
<dialog aria-labelledby="dialog-title">
  <h2 id="dialog-title">Confirm Deletion</h2>
  <p>This action cannot be undone.</p>
</dialog>
  • Focus management is automatic for showModal() — focus moves into the dialog and is trapped.
  • Escape key closes the dialog — this is expected behaviour.
  • For non-modal dialogs (show()), you may need to manage focus manually.

Always ensure the dialog has a clear way to be dismissed (a close button, cancel button, or form submission).

Complete Dialog Example

html
<!-- Trigger button -->
<button id="openBtn">Delete Account</button>

<!-- Modal dialog -->
<dialog id="confirmDialog" aria-labelledby="dlg-title">
  <h2 id="dlg-title">Confirm Deletion</h2>
  <p>Are you sure you want to delete your account? This cannot be undone.</p>

  <form method="dialog">
    <button value="cancel">Cancel</button>
    <button value="confirm">Delete</button>
  </form>
</dialog>

<script>
  const dialog = document.getElementById('confirmDialog');
  const openBtn = document.getElementById('openBtn');

  openBtn.addEventListener('click', () => dialog.showModal());

  dialog.addEventListener('close', () => {
    if (dialog.returnValue === 'confirm') {
      console.log('Account deleted');
    }
  });
</script>

What is the difference between dialog.show() and dialog.showModal()?

Ready to practice?

Create your free account to access the interactive code editor, run challenges, and track your progress.