Home / Snippets / UI Components /
Dialog modal
Native <dialog> element — accessible, keyboard-friendly, styleable.
Confirm action
Are you sure you want to proceed? This action cannot be undone.
Quick implementation
/* HTML: <dialog class="modal">...</dialog> */
/* JS: dialog.showModal() to open, dialog.close() to close */
.modal {
border: 1px solid oklch(0.30 0.02 260);
border-radius: 1rem;
background: oklch(0.17 0.02 260);
color: oklch(0.93 0.01 260);
padding: 2rem;
max-width: 24rem;
width: min(90%, 24rem);
}
.modal::backdrop {
background: oklch(0 0 0 / 0.6);
backdrop-filter: blur(4px);
}
/* Open animation */
.modal[open] {
animation: modal-in 0.2s ease-out;
}
@keyframes modal-in {
from {
opacity: 0;
transform: scale(0.95) translateY(-0.5rem);
}
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building a modal dialog component.
Goal: A dialog modal using the native <dialog> element with styled backdrop and open animation.
Technical constraints:
- Use the native <dialog> element — not a div with role="dialog".
- Open with dialog.showModal(), close with dialog.close().
- Style ::backdrop with semi-transparent overlay and optional backdrop-filter: blur.
- Use oklch() for all colors, not hex or rgba().
- Open animation: scale + translateY with opacity fade-in.
- Max width: 24rem with width: min(90%, 24rem) for mobile.
Framework variant (pick one):
A) Vanilla HTML + CSS + minimal JS (showModal/close).
B) React component — accept isOpen, onClose, title, children props.
Edge cases to handle:
- Escape key closes the dialog (native behavior — don't break it).
- Focus trap is handled by the browser with showModal() — do not add custom focus trap.
- Scrolling the body should be prevented while the dialog is open.
- Respect prefers-reduced-motion for the open animation.
Return HTML + CSS + minimal JS.
Why this matters in 2026
The <dialog> element provides focus trapping, Escape key handling, and top-layer rendering for free. Before it shipped, every modal required hundreds of lines of JavaScript for accessibility. Now the browser handles the hard parts — your job is just CSS styling.
The logic
dialog.showModal() places the dialog in the top layer, above all other content, and renders the ::backdrop pseudo-element behind it. The dialog is automatically centered and trapped for focus. The ::backdrop styles add a dark overlay with optional blur. The [open] attribute selector triggers the entrance animation.
Accessibility & performance
The native <dialog> element provides built-in focus trapping — when opened with showModal(), Tab cycles only within the dialog. Escape closes it. Screen readers announce it as a dialog. Do not add role="dialog" — it's already implied. The backdrop-filter: blur() uses GPU compositing but can be expensive on large pages; test on low-end devices.