CSS Modal Dialog with the Native dialog Element

Modal dialogs without a JavaScript library

The old way was a custom overlay plus JavaScript for open/close, ESC key, click-outside, focus trap, and z-index. The dialog element and showModal() handle all of that.

Old way 15+ lines
.overlay   {  position: fixed;  inset: 0;  background: rgb(0 0 0 / .5);}/* JS: addEventListener click, keydown ESC, focus trap,   aria-hidden, body scroll lock, z-index stacking */
Modern
6 lines
dialog   {  padding: 1rem;}dialog::backdrop   {  background: rgb(0 0 0 / .5);}/* JS: dialog.showModal(); dialog.close(); */
Widely available Since 2022 96% global usage

This feature is well established and works across many devices and browser versions. It has been available across browsers since 2022.

Safe to use without fallbacks.

37+
98+
15.4+
79+
click Open — ESC or the close button dismisses
Native dialog

Top layer. Focus trapped. ESC closes. No overlay div, no z-index fights.

dialog.showModal() — top layer, focus trapped

Built-in behavior

ESC to close, click outside to close, and focus trapping come free. No extra JS.

Accessible by default

The browser manages focus and return focus. Top layer stacking is handled for you.

One element

No overlay div, no z-index wars. Style dialog and ::backdrop and you are done.

Lines Saved
15+ → 6
No overlay or focus-trap JS
Old Approach
Custom overlay + JS
ESC, click-outside, focus trap, z-index
Modern Approach
dialog + showModal()
::backdrop, top layer

How it works

The old approach meant a fixed overlay div, JavaScript to open and close it, keydown listeners for Escape, click-outside detection, focus trapping so tab stays inside the modal, and careful z-index management. Easy to get wrong or forget a detail.

The modern approach is a single <dialog> element. Call dialog.showModal() to open it: the browser puts it in the top layer, traps focus, and provides ESC and click-outside behavior. Style the ::backdrop pseudo-element for the dimmed background. No overlay div, no focus library.

ESC