How to Style Dialogs with the CSS :modal Pseudo-Class
The CSS :modal pseudo-class allows developers to target
and style elements that enter a modal state, during which interaction
with the rest of the document is blocked. When applied to HTML
<dialog> elements, :modal differentiates
a dialog opened as an interactive, focus-trapping modal from one
displayed as a standard, non-modal inline element. This article covers
how the :modal pseudo-class works with the native
<dialog> element, why it is necessary, and practical
examples of its implementation.
The Distinction Between Modal and Non-Modal Dialogs
The native <dialog> element can be opened in two
distinct ways using JavaScript:
dialog.show(): Opens the dialog as a non-modal element. Users can still interact with the rest of the page, and the dialog behaves similarly to a standard positioned container.dialog.showModal(): Opens the dialog in the top layer of the browser. It restricts interaction to the dialog itself, traps focus, creates a default dark::backdrop, and activates the:modalstate.
Both methods apply the HTML open attribute to the
<dialog> tag (e.g.,
<dialog open>), which means the CSS selector
dialog[open] cannot distinguish between a modal and a
non-modal dialog. The :modal pseudo-class solves this issue
by matching the element only when it is displayed via
showModal().
Why Use the :modal
Pseudo-Class?
Using :modal prevents unwanted style bleeding between
standard inline alerts and true overlay dialogs. It provides several
functional advantages:
- Conditional Visual Hierarchy: You can assign prominent drop shadows, centered fixed positions, or larger dimensions exclusively when the element takes over the screen.
- Responsive Behavior: A dialog can function as an
inline drawer or card on wide desktop screens using
.show(), while switching to a full-screen overlay using.showModal()on mobile viewports. - Separation of Concerns: You avoid relying on custom
JavaScript classes (such as
.is-modal) to track state, leveraging native browser-level state detection instead.
Implementation Example
Consider an application with both inline popovers and full-screen prompt dialogs using the same HTML markup:
<dialog id="userDialog">
<h2>Confirm Action</h2>
<p>Are you sure you want to proceed?</p>
<button id="closeBtn">Close</button>
</dialog>Using CSS, you can define base styles for
<dialog>, and then apply specific enhancements
exclusively when opened modally:
/* Base styles applied whenever the dialog is open */
dialog[open] {
padding: 1.5rem;
border: 1px solid #ccc;
border-radius: 8px;
}
/* Styles applied ONLY when opened via showModal() */
dialog:modal {
max-width: 500px;
width: 90%;
border: 2px solid #0056b3;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
margin: auto;
}
/* Styling the backdrop that appears exclusively with modal dialogs */
dialog:modal::backdrop {
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(3px);
}Browser Support
The :modal pseudo-class is part of the CSS Selectors
Level 4 specification and is supported across all modern evergreen
browsers, including Chrome, Edge, Firefox, and Safari. It works out of
the box with the HTML <dialog> element without
requiring polyfills or vendor prefixes.