dialog

The native HTML modal dialog element with built-in backdrop, focus trapping, and keyboard handling.

Description

The <dialog> element provides a native way to create modal dialogs and pop-up windows. It handles complex accessibility requirements automatically, including focus trapping, ESC to close, and proper ARIA semantics.

There are two ways to open a dialog:

  • HTML Invokers API (recommended) - command="show-modal" / command="close"
  • showModal() / show() - JavaScript methods

Invokers API (Declarative)

The Invokers API lets you open and close dialogs declaratively with HTML attributes - no JavaScript required.

Invokers API Demo

This dialog opens and closes using only HTML attributes - no JavaScript!

<!-- Trigger button --> <button commandfor="my-dialog" command="show-modal">Open Dialog</button> <!-- Dialog --> <dialog id="my-dialog"> <header> <h3>Dialog Title</h3> </header> <p>Content goes here.</p> <footer> <button commandfor="my-dialog" command="close">Close</button> </footer> </dialog>

Available Commands

Command Description
show-modal Opens dialog as modal (equivalent to showModal())
close Closes the dialog (equivalent to close())
request-close Requests closure (can be cancelled with cancel event)

Browser Support

Invokers API is supported in Chrome 135+, Edge 135+, Safari TP, and Firefox Nightly. Include the polyfill for broader support:

<script type="module" src="https://unpkg.com/invokers-polyfill"></script>

When to Use

  • Confirmation dialogs: Confirm destructive actions before proceeding
  • Form dialogs: Collect user input in an overlay
  • Alert messages: Display important information that requires acknowledgment
  • Media lightboxes: Show images or videos in a focused overlay
  • Settings panels: Quick access to settings without navigation

When Not to Use

  • For inline expandable content - use <details>
  • For tooltips or popovers - use <tooltip-wc>
  • For toast notifications - use <toast-wc>
  • For non-blocking information - avoid interrupting user flow

showModal() vs show()

The key difference between these two methods affects focus, backdrop, and user interaction:

Feature showModal() show()
Backdrop Yes - via ::backdrop No
Focus trap Yes - focus stays inside No - focus can leave
ESC to close Yes - native behavior No
Inert background Yes - page is non-interactive No - page remains interactive
Top layer Yes - above all content Normal stacking context

Modal Dialog (Recommended)

Modal Dialog

This is opened with showModal(). Notice the backdrop and try pressing ESC to close.

// Open as modal document.getElementById('my-dialog').showModal(); // Close document.getElementById('my-dialog').close();

Non-Modal Dialog

Non-Modal Dialog

This is opened with show(). No backdrop, and you can still interact with the page.

Backdrop Styling

The ::backdrop pseudo-element styles the overlay behind modal dialogs.

dialog::backdrop { background: oklch(0% 0 0 / 0.5); backdrop-filter: blur(2px); }

Backdrop Animation

Vanilla Breeze includes smooth fade animation for the backdrop (respects prefers-reduced-motion):

@media (prefers-reduced-motion: no-preference) { dialog[open]::backdrop { animation: backdrop-fade var(--duration-normal) var(--ease-out); } } @keyframes backdrop-fade { from { opacity: 0; } to { opacity: 1; } }

Form method="dialog"

Forms inside dialogs can use method="dialog" to close the dialog when submitted, passing the submit button's value as the return value.

Choose an Option

Select your preference:

<dialog id="choice-dialog"> <form method="dialog"> <p>Select your preference:</p> <footer> <button type="submit" value="cancel">Cancel</button> <button type="submit" value="confirm">Confirm</button> </footer> </form> </dialog> <script> const dialog = document.getElementById('choice-dialog'); dialog.addEventListener('close', () => { console.log('User chose:', dialog.returnValue); // "cancel" or "confirm" }); </script>

Variants

Basic Dialog

Basic Dialog

A simple dialog with header, content, and footer.

Confirmation Dialog

Confirm Deletion

Are you sure you want to delete this item? This action cannot be undone.

Dialog with Form

Subscribe to Newsletter

Scrollable Content

Terms and Conditions

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam in dui mauris. Vivamus hendrerit arcu sed erat molestie vehicula. Sed auctor neque eu tellus rhoncus ut eleifend nibh porttitor.

Ut in nulla enim. Phasellus molestie magna non est bibendum non venenatis nisl tempor. Suspendisse dictum feugiat nisl ut dapibus. Mauris iaculis porttitor posuere.

Praesent id metus massa, ut blandit odio. Proin quis tortor orci. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet.

Nunc eu ullamcorper orci. Quisque eget odio ac lectus vestibulum faucibus eget in metus. In pellentesque faucibus vestibulum. Nulla at nulla justo, eget luctus tortor.

Dialog Structure

For consistent styling, use this recommended structure with header, content, and footer:

<dialog> <header> <h3>Dialog Title</h3> </header> <!-- Main content (section or direct content) --> <p>Dialog content goes here.</p> <footer> <button type="button" class="secondary">Cancel</button> <button type="button">Confirm</button> </footer> </dialog>

Structural CSS

dialog { max-inline-size: min(90vw, 32rem); max-block-size: 85dvh; padding: var(--size-l); border: none; border-radius: var(--radius-l); background: var(--color-surface); color: var(--color-text); box-shadow: /* elevation shadow */; } dialog > header { margin-block-end: var(--size-m); } dialog > footer { margin-block-start: var(--size-l); display: flex; flex-wrap: wrap; gap: var(--size-s); justify-content: flex-end; }

JavaScript API

Methods

Method Description
showModal() Opens dialog as modal with backdrop and focus trap
show() Opens dialog as non-modal
close(returnValue?) Closes dialog, optionally setting returnValue

Properties

Property Type Description
open boolean Whether the dialog is currently open
returnValue string Value set by close() or form submission

Events

Event Description
close Fired when the dialog is closed
cancel Fired when ESC is pressed (can be prevented)
const dialog = document.querySelector('dialog'); // Open as modal dialog.showModal(); // Listen for close dialog.addEventListener('close', () => { console.log('Dialog closed with:', dialog.returnValue); }); // Prevent ESC from closing dialog.addEventListener('cancel', (event) => { event.preventDefault(); });

Accessibility

Native Features

The <dialog> element provides these accessibility features automatically:

  • Focus trapping: Tab key cycles through focusable elements inside the dialog
  • Focus restoration: Focus returns to the triggering element when closed
  • Inert background: Background content is non-interactive when modal is open
  • ESC to close: Standard keyboard dismissal (can be prevented)
  • ARIA semantics: Automatically has role="dialog"

Best Practices

  • Include a visible close button
  • Use a heading in the dialog for screen reader context
  • Keep dialogs focused - don't include unrelated content
  • Provide keyboard alternatives for all actions

Keyboard Support

Key Action
Tab Move focus between focusable elements (trapped inside)
Shift + Tab Move focus backwards (trapped inside)
Escape Close the modal dialog

Animation

The dialog includes smooth entry animations that respect prefers-reduced-motion:

@media (prefers-reduced-motion: no-preference) { dialog[open] { animation: dialog-open var(--duration-normal) var(--ease-out); } } @keyframes dialog-open { from { opacity: 0; transform: scale(0.95) translateY(-1rem); } to { opacity: 1; transform: scale(1) translateY(0); } }

Size Variants

Use data-size to control dialog width:

Attribute Width Use Case
data-size="s" 24rem (384px) Simple confirmations, alerts
default 32rem (512px) Standard dialogs, forms
data-size="l" 48rem (768px) Complex content, tables
data-size="full" 95vw / 95dvh Full-screen experiences

Small Dialog

Compact size for simple confirmations.

Large Dialog

More space for complex content, tables, or multi-step forms.

Full Screen Dialog

Full-screen experience for immersive content or complex workflows.

Backdrop Click to Close (Optional)

Native dialogs do not close when clicking the backdrop. If you want this behavior, add this small script:

// Add backdrop click to close for all dialogs document.querySelectorAll('dialog').forEach(dialog => { dialog.addEventListener('click', e => { if (e.target === dialog && !dialog.hasAttribute('data-no-backdrop-close')) { dialog.close(); } }); });

To prevent backdrop close for specific dialogs (e.g., forms with unsaved data), add data-no-backdrop-close:

<dialog id="form-dialog" data-no-backdrop-close> <!-- User must explicitly click Cancel or Save --> </dialog>

Drawer Variants

Use data-position to turn any dialog into a slide-in drawer panel. No JavaScript required.

Attribute Position Use Case
data-position="end" Right (in LTR) Navigation, settings panels
data-position="start" Left (in LTR) Sidebar, filters
data-position="bottom" Bottom Mobile action sheets, share menus
data-position="top" Top Banners, announcements

Settings

Slide-in panel from the right edge.

Share

Mobile-friendly bottom drawer.

<!-- Right drawer --> <button commandfor="nav-drawer" command="show-modal">Menu</button> <dialog id="nav-drawer" data-position="end"> <header><h3>Navigation</h3></header> <section> <nav>...</nav> </section> <footer> <button commandfor="nav-drawer" command="close">Close</button> </footer> </dialog>

Drawers inherit all dialog features: Invokers API, ESC to close, focus trapping, backdrop, and data-size variants. Slide animations respect prefers-reduced-motion.

View the interactive drawer demo →

Related Elements

  • <details> - For inline expandable content (not overlays)
  • <form> - Forms inside dialogs with method="dialog"
  • <button> - Trigger buttons for opening dialogs

Browser Support

The <dialog> element is supported in all modern browsers.

Invokers API: Chrome 135+, Edge 135+, Safari TP, Firefox Nightly. Use the invokers-polyfill for broader support.