Most modals still get built from a div, a high z-index and a keydown listener somebody has to remember to write. The native dialog element makes that unnecessary. Calling showModal() puts it in the top layer, draws a ::backdrop and makes the rest of the document inert. MDN Web Docs lists the element as Baseline widely available, and it has worked across browsers since March 2022.

Checkbox toggles and :target links can open an overlay with no JavaScript at all. Neither one closes on Escape, though, and neither makes the page behind it inert. That gap is what separates a styled box from a true modal dialog.

What Is a CSS Modal, and What Is It Not?

See the Pen
Simple Confirmation Popup
by Adventures in Missions (@adventuresinmissions)
on CodePen.

Plenty of overlays get called modals without earning the name. In CSS terms, a modal is built from HTML and CSS (the dialog element, the ::backdrop pseudo-element, fixed positioning) and shows focused content above the page, blocking everything underneath until the user dismisses it.

CSS covers the look and the layering. Opening and closing takes a few lines of JavaScript or a declarative HTML attribute, unless you settle for a plain overlay toggled through :target or :checked.

Designers know the pattern as a modal in UI design, and the CSS version only changes how it gets built. What makes a modal real is enforcement. The browser makes the rest of the page inert instead of just covering it.

Modal dialog vs non-modal dialog

A dialog opened with showModal() is the modal kind. The rest of the page becomes inert, Esc closes it by default, and assistive technology sees it as aria-modal=”true”.

Open one with show() or the open attribute and you get the non-modal kind. The page stays interactive, Esc does nothing by default, and the dialog is exposed as aria-modal=”false”.

Go non-modal only when users have to keep working behind the box, like with an inspector panel.

Modal vs popover and lightbox

A popover is the non-modal cousin. It also lands in the top layer, but an auto popover closes on an outside click or Esc and never blocks the page (MDN Web Docs).

Lightboxes are modals built around media. Hans Christian Reinl’s CSS Modal library, for example, ships text, photo gallery, video and stackable variants.

The decision rule is short. If the user must respond before moving on, use a modal. If the content is closer to a hint or a menu (a tooltip, say), use a popover.

How the Dialog Element Works as a Modal

Call showModal() on a dialog and it lands in the top layer, gets a ::backdrop behind it, and turns every other element in the document inert (MDN Web Docs).

That one call replaces most of what div-based tutorials build by hand. Focus moves to the first focusable element inside the dialog, or to whatever carries the autofocus attribute. Escape closes it, and when several modals are open it only closes the last one shown. The browser exposes it with an implicit aria-modal=”true”, much like a custom dialog role, and the background goes inert, so clicks and tab stops skip it.

A div with role=”dialog” has to rebuild every one of those, and MDN says as much. Hyring’s modal tutorial, for instance, adds a document-level keydown listener for Escape, sets overflow: hidden on the body, and writes the ARIA attributes (role, aria-modal, aria-labelledby) by hand.

Scroll locking isn’t on MDN’s list of built-in behaviors, so it gets its own section further down.

One trap. Never put tabindex on the dialog itself. MDN warns against it because the dialog isn’t interactive and doesn’t take focus.

Top layer vs position fixed and z-index

Top layer elements stack last in, first out above all page content, and each one gets its own ::backdrop (MDN Web Docs). Nothing in the DOM tree can trap them.

A fixed overlay with a z-index is a different story, because it stays inside its ancestors’ stacking contexts. A parent with a transform becomes the containing block for a fixed child, so the modal can end up sitting below a sticky header however high the z-index climbs.

Native dialog ends the z-index arms race.

Which CSS Modal Method Should You Use?

See the Pen
CSS Responsive Modal
by Thom Griggs (@thomgriggs)
on CodePen.

Use the native dialog element with showModal(). It’s the only option here where the browser supplies the inert background, Escape handling and focus placement.

Several tutorials that rank for this topic teach the checkbox hack or :target, which is exactly why those techniques keep getting copied into production. Treat them as demo techniques.

If you want zero JavaScript to open and close, a dialog with commandfor does it, plus a showModal() click listener for older browsers. A :target overlay only makes sense on a static page where nobody needs Escape. For everything else, showModal().

Capability comparison

MethodOpens without JavaScriptEscape closesBackground inert
Dialog with showModal()NoYes, built inYes, built in
Dialog with commandforYesYes, built inYes, built in
:target overlayYesManual, needs JavaScriptManual
Checkbox hackYesManual, needs JavaScriptManual
Div overlay with JS toggleNoManual, needs JavaScriptManual

The native rows come from MDN’s dialog reference. The CSS-only rows follow the limits reported by The Admin Bar (no Escape, no backdrop click) and Hongkiat (no focus handling).

Pros and cons of each method

The native dialog with showModal() hands you the inert background, Escape and focus placement for free. What it costs is a JavaScript call to open it.

Adding commandfor removes even that. The dialog opens and closes without a script, even before JavaScript loads. It’s only newly available in Baseline terms, though, so older browsers need the showModal() fallback.

The :target overlay is pure CSS and a link. There’s no Escape key, no focus handling, and the URL fragment changes.

The checkbox hack is pure CSS too and leaves the URL alone, but it has the same missing Escape and focus handling, and the state lives in a form control.

A div overlay with a JS toggle works in any browser and gives you full control. Inert, Escape, focus and ARIA are all yours to build.

Browser support by method

Support dates decide how much fallback code each method needs.

  • The dialog element has been supported across browsers since March 2022 and is Baseline widely available (MDN Web Docs).
  • Invoker Commands (commandfor) became Baseline newly available in December 2025 (MDN Web Docs).
  • closedby shipped in Chrome 134 (March 2025) and Firefox 141 (July 2025). Safari doesn’t have it, and Baseline marks it limited availability (WebDX web-features data).
  • :target is Baseline widely available and has been supported across browsers since July 2015 (MDN Web Docs).

MDN’s closedBy reference carries the same limited availability label. Skeleton’s dialog docs list Firefox 136 for closedby, while the web-features dataset says 141, and the dataset is the primary source.

Until Safari ships closedby, a build that relies on it needs a click-listener fallback, which makes cross-browser compatibility checks part of the job.

How to Build a CSS Modal with the Dialog Element

Start with the markup, then wire up opening and closing, then style it.

  1. Write a dialog with a heading, the content and a close button, and point aria-labelledby at the heading.
  2. Put autofocus on the close button when nothing else needs immediate input, as MDN recommends.
  3. Add a trigger button that calls showModal() on click.
  4. Close it with close(), or put the actions inside a form with method=”dialog” so the browser closes the dialog and sets returnValue.
  5. Style the box with width and max-height, then style the ::backdrop.
<button id="open-modal">Open modal</button>

<dialog id="modal" aria-labelledby="modal-title">
<h2 id="modal-title">Subscribe</h2>
<p>Short content goes here.</p>
<button id="close-modal" autofocus>Close</button>
</dialog>

<script>
const modal = document.querySelector("#modal");
document.querySelector("#open-modal").addEventListener("click", () => modal.showModal());
document.querySelector("#close-modal").addEventListener("click", () => modal.close());
</script>

Center and size the modal

See the Pen
Simple, flexible, and responsive flexbox-based modal
by Bryan Chalker (@bchalker)
on CodePen.

The browser already centers a modal dialog. The HTML Standard’s default rules set position: fixed, inset-block to 0 and margin: auto, and cap both max-width and max-height at calc(100% – 6px – 2em).

So the CSS you write is short. Set a width, cap the height, and leave positioning alone.

dialog {
width: min(32rem, calc(100% - 2rem));
max-height: min(40rem, 90svh);
padding: 1.5rem;
border: 0;
border-radius: 0.75rem;
}

A global reset such as * { margin: 0 } removes margin: auto and pushes the dialog to the top-left corner. The default max-height cap also leaves a visible gap on full-height modals, so set max-height: none (a fix documented by Simon Willison).

Watch display too. Putting display: flex on the dialog selector overrides the closed state, so scope it to dialog[open].

For the height cap, prefer svh over vh, since the small, large and dynamic CSS viewport units account for mobile browser toolbars and plain vh does not.

Style the backdrop

See the Pen
Prompt Dialog with background blur
by Tuomas Hatakka (@ndne)
on CodePen.

The default backdrop is nearly invisible. The HTML Standard’s default style sheet sets it to rgba(0, 0, 0, 0.1).

Replace it with a stronger color and add a blur. The backdrop-filter property has been Baseline newly available since September 2024, when Safari 18 shipped it (WebDX web-features data), so keep the solid color dark enough to work without the blur.

dialog::backdrop {
background: rgb(0 0 0 / 0.6);
backdrop-filter: blur(4px);
}

The backdrop only exists when the dialog opens through showModal(). A dialog opened with show() or the open attribute has none, per MDN.

How to Build a CSS Modal Without JavaScript

See the Pen
Pure CSS Modal
by Mark Holmes (@SMLMRKHLMS)
on CodePen.

A :target link and a checkbox toggle can both open a modal without JavaScript, and so can the commandfor attribute on a dialog button. Only that last one gives you a true modal.

The :target method

See the Pen
CSS Modal using :target Selector
by Homer Gaines (@xirclebox)
on CodePen.

A link to #modal makes the element with that id the document’s target, and the :target pseudo-class styles it. A link to # closes it.

.modal:not(:target) { display: none; }
.modal:target { position: fixed; inset: 0; display: grid; place-items: center; }

One side effect is the URL fragment changing, so the Back button closes the modal. MDN notes that the target element updates on history navigation.

The limits are documented. The Admin Bar reports that Escape does not close it, and Hongkiat points out that focus never moves into the modal or back to the trigger.

Backdrop clicks are where sources disagree. The Admin Bar’s build cannot close on a backdrop click, but Envato Tuts+ closes its modal that way by making the overlay itself an anchor that points back to the trigger.

Link-based overlays work for outside clicks. Escape still needs JavaScript.

The checkbox hack

See the Pen
Basic CSS-Only Modal
by Timothy Long (@timothylong)
on CodePen.

A hidden checkbox holds the state, a label opens and closes it, and the :checked pseudo-class shows the modal. The modal has to follow the checkbox in the DOM so the sibling selector can reach it.

It shares the :target limits (no Escape, no focus handling) and adds a form control with no dialog meaning. Demos only, honestly.

Declarative dialog with commandfor

This is the only no-JavaScript route that keeps native modal behavior. A button with command=”show-modal” and commandfor pointing at the dialog’s id opens it modally, and command=”close” closes it (MDN Web Docs).

<button commandfor="my-dialog" command="show-modal">Open dialog</button>

<dialog id="my-dialog">
<p>No click handler needed.</p>
<button commandfor="my-dialog" command="close">Close</button>
</dialog>

Because the browser handles the command, the button works without waiting for a JavaScript bundle to download and run. Dialogs respond to show-modal, close and request-close.

Keep a small click listener as a fallback for browsers that predate the attributes.

Focus, Keyboard and Screen Reader Behavior

A native modal dialog contains focus at the page level only. Tab can still reach the browser’s own interface, and that’s deliberate.

It departs from the W3C pattern for modal dialogs, which keeps Tab inside the dialog.

Focus containment: ARIA pattern vs native behavior

Under the W3C ARIA Authoring Practices, Tab and Shift+Tab never move focus outside the dialog, and Tab on the last tabbable element wraps to the first.

A native dialog opened with showModal() behaves differently. Tab and Shift+Tab can reach the address bar, the tabs and extensions, while the page behind the dialog stays unreachable.

A WHATWG HTML issue (#8339) records why the native behavior stays. Keyboard users can open a new tab or change a browser setting without closing the dialog.

So skip the JavaScript focus trap on a native dialog. Add one only to div-based modals, where nothing else keeps focus off the page.

Where focus lands and where it returns

With long content, put tabindex=”-1″ on a static element at the top, such as the title, and focus that, so the start of the text does not scroll out of view. For a destructive action, focus the least destructive button, like Cancel. A simple confirmation can focus the most used control, such as OK or Continue.

All of that comes from the W3C pattern notes. The earlier tabindex warning applies to the dialog element itself, not to a static child inside it.

On close, focus should return to the invoking element unless it no longer exists. Sources disagree on how reliably the native dialog does this: UXPin and OpenReplay say close() restores focus to the trigger, while Oxford University Press’s accessibility guide says the return is not guaranteed in every case.

A three-line close listener removes the doubt.

let trigger;
openBtn.addEventListener("click", () => { trigger = document.activeElement; modal.showModal(); });
modal.addEventListener("close", () => trigger?.focus());

Dismissal with closedby

closedby valueEsc or back gestureOutside click
anyClosesCloses
closerequestClosesDoes nothing
noneDoes nothingDoes nothing

Without the attribute, a dialog opened with showModal() behaves as closerequest (MDN Web Docs). Esc fires a cancel event first, which code can prevent in some cases.

Outside-click dismissal alone fails keyboard and touch users, who may have no equivalent gesture. Ship a visible close button every time, as the W3C pattern strongly recommends.

Labels for screen readers

Name the dialog through aria-labelledby pointing at a visible title, or through aria-label.

The W3C pattern makes aria-describedby optional and advises skipping it when the content has lists, tables or several paragraphs, because screen readers announce a description as one unbroken string. Mark a custom dialog aria-modal=”true” only when code blocks all interaction outside it and the styling obscures the page. A native dialog meets both conditions by default.

How to Stop the Page Scrolling Behind a Modal

Call showModal() and the page behind the dialog stops accepting clicks, but it can still scroll. Scroll locking is a separate CSS job, and OpenReplay’s scroll-lock guide puts the split plainly: the method blocks interaction, not background scrolling.

Lock the page with overflow

Set overflow: hidden on the root while a dialog is open. Using :has() ties the lock to the open attribute that showModal() sets, so JavaScript has nothing to clean up (Frontend Masters).

html:has(dialog[open]) { overflow: hidden; }

It isn’t bulletproof. Touch scrolling on iOS Safari can bypass overflow: hidden on the body (OpenReplay). And a page with the html element set to overflow-y: scroll keeps scrolling when only the body is locked, so target html instead.

For iOS Safari, OpenReplay’s fallback is a fixed-position body that saves and restores the scroll position.

Contain scroll chaining on the dialog

overscroll-behavior: contain stops scrolling inside the dialog from spilling into the page. MDN and the web-features dataset list the property as limited availability, so it is not yet Baseline: Safari does not support it.

Sources conflict on whether it works. Frontend Masters tested it on the dialog and the ::backdrop and saw no lock, while OpenReplay says it prevents chaining but not scrolling that starts on the backdrop or the body.

Both can be true. The property stops chaining, and it does not lock a page the user scrolls directly. With Safari still missing support, treat it as a layer on top of the overflow lock, never a replacement for it.

Prevent layout shift when the scrollbar disappears

According to the web-features dataset, scrollbar-gutter has been Baseline newly available since December 2024, when Safari 18.2 shipped it. Setting it to stable reserves the scrollbar’s space, so locking the page does not push content sideways.

Overlay scrollbars have no gutter, so the property does nothing there (MDN Web Docs). When no scrollbar shows, it leaves a blank strip down the side with no inherited background. A Chrome bug also keeps it from affecting position: fixed elements.

Apply it to html rather than body, and test any fixed header.

html { scrollbar-gutter: stable; }
html:has(dialog[open]) { overflow: hidden; }
dialog { overscroll-behavior: contain; }

How to Animate a Modal Opening and Closing

See the Pen
Pure CSS Animated Modals
by Tom (@TomJ1588)
on CodePen.

Animating a dialog needs @starting-style for the entry state and a transition on display with allow-discrete. A transition on overlay keeps the dialog in the top layer while it exits (MDN Web Docs).

@starting-style has been Baseline newly available since August 2024, when Firefox 129 shipped it, according to the web-features dataset. The overlay property is the weak link. The same dataset lists it as limited availability, supported only in Chrome and Edge 117 and later.

Treat overlay as progressive enhancement. Without these features the dialog still opens, it just appears without the transition (web.dev).

dialog {
opacity: 0;
transform: translateY(1rem);
transition: opacity 0.2s ease-out, transform 0.2s ease-out,
overlay 0.2s allow-discrete, display 0.2s allow-discrete;
}

dialog[open] { opacity: 1; transform: none; }

@starting-style {
dialog[open] { opacity: 0; transform: translateY(1rem); }
}

dialog::backdrop {
background: rgb(0 0 0 / 0);
transition: background 0.2s, overlay 0.2s allow-discrete, display 0.2s allow-discrete;
}

dialog[open]::backdrop { background: rgb(0 0 0 / 0.6); }

@starting-style {
dialog[open]::backdrop { background: rgb(0 0 0 / 0); }
}

Write allow-discrete inside the transition shorthand. If transition-behavior comes before the shorthand, the browser ignores it (web.dev).

Keyframes instead of transitions

Keyframe animations are simpler on the dialog and weaker on the backdrop. With CSS keyframes you skip @starting-style and allow-discrete, and a display value placed in a keyframe holds for the whole animation.

The catch is the backdrop. It can’t fade out this way, because the browser removes it the moment the dialog closes (MDN Web Docs).

Duration and reduced motion

MDN’s demos run 0.7s, which is slow for a component people open often. Drop it to around 200ms.

prefers-reduced-motion has been supported in every major browser since January 2020 and is Baseline widely available, and MDN lists scaling and panning of large objects among the vestibular motion triggers. WCAG 2.3.3 asks that interaction-triggered motion can be switched off, at Level AAA.

Inside a media query for the reduce setting, drop the transform from the transition list and keep a short fade.

@media (prefers-reduced-motion: reduce) {
dialog {
transition: opacity 0.1s linear, overlay 0.1s allow-discrete, display 0.1s allow-discrete;
}
}

When a CSS Modal Falls Short

A CSS modal is the wrong tool when the content isn’t critical, when it blocks the first view of a page, when users hold unsaved input, or when the form sits on a phone with the keyboard open.

Content that does not deserve an interruption

See the Pen
Evil Cookie Policy
by Álex (@lerida)
on CodePen.

Nielsen Norman Group’s 2017 guidance lists the costs: a modal demands immediate attention, interrupts the workflow, adds a dismissal task and blocks background content.

That price is worth paying for critical warnings and input required to continue. It isn’t worth paying for newsletter prompts, or for upsells that need information the modal hides. A flow that takes several steps probably deserves a full page.

NN/g’s example is Walmart.com, whose older checkout used a modal login prompt and later dropped it.

Landing pages and search visibility

Google Search Central says intrusive dialogs and interstitials make content harder for search engines to understand, and it recommends small banners over overlays that obscure the whole page (documentation updated December 2025).

The case to avoid is a modal that opens as soon as someone reaches a landing page from a search result. NN/g’s study caught GoodHousekeeping.com showing a newsletter modal within 3 seconds of a first homepage visit, over a full-screen photo that removed all context.

Age gates are exempt from Google’s guidance. Google still suggests overlaying the content so some of it stays indexable.

Unsaved input and forced closing

The cancel event lets code stop Escape from closing a dialog, but only in some cases.

Browsers added an anti-abuse rule. The cancel event fires only after user activation, and a second close request with no activation in between goes through (WICG CloseWatcher explainer). Google’s Material Web project tracks the same gap as an open issue, listing the Android back button and a double Escape as gestures that cannot be canceled.

Never rely on preventDefault to protect form data. Save drafts while the user types.

Forms and mobile keyboards

The svh, lvh and dvh units do not react to the on-screen keyboard (OpenReplay), so a modal capped in those units can still hide a focused field behind the keyboard.

Keep form modals short, let the content scroll inside the dialog, and move long forms to their own page. Test every form modal on a real phone.

Examples of CSS modals 

Draggable Translucent Modal

See the Pen
Draggable Translucent Modal
by Jesse Couch (@designcouch)
on CodePen.

Details modal

See the Pen
Details modal
by Niels Voogt (@NielsVoogt)
on CodePen.

Strikethrough Text With Explanations In Modal On Hover

See the Pen
Strike through explanations
by eightarmshq (@EightArmsHQ)
on CodePen.

CSS Only Line Animated Modal

See the Pen
CSS Only Line Animated Modal
by Tom (@TomJ1588)
on CodePen.

Simple Dialog Effects

See the Pen
Simple dialog effects
by Ying Zhang (@dodozhang21)
on CodePen.

Pop Under Modal for Movie Ticket Snippet

See the Pen
Movie Ticket Animation – Loop 23
by Jorge Mendes (@jorgemoovein-the-bashful)
on CodePen.

CSS Modal

See the Pen
CSS Modal
by Pete Nawara (@petebot)
on CodePen.

Pop-Up With Blurred Background Animation

See the Pen
Pop-up with blurred background animation
by Benjamin Dalton (@jaeming)
on CodePen.

Login Modal With Floating

See the Pen
Login Form with floating placeholder and light button
by Saijo George (@SaijoGeorge)
on CodePen.

Pure CSS Modal Box

See the Pen
Pure CSS modal box
by Kasper Mikiewicz (@Idered)
on CodePen.

Modal Animation Physics

See the Pen
Modal Animation Physics
by Tey Tag (@pix3l)
on CodePen.

Morphing Modal Window

See the Pen
Morphing Modal Window
by CodyHouse (@codyhouse)
on CodePen.

Pure CSS Modal + Slider

See the Pen
Pure CSS Modal + Slider
by Marvin Orendain (@marv117)
on CodePen.

Pure CSS Modal Popup

See the Pen
Pure CSS modal
by Austin Lord (@ohnoitsaustin)
on CodePen.

Modal Window Destroy Concept

See the Pen
Modal window destroy concept
by LegoMushroom (@sol0mka)
on CodePen.

Login Modal

See the Pen
login modal
by Mert Cukuren (@knyttneve)
on CodePen.

Modal Dialog

See the Pen
Modal Dialog
by David Fitas (@dfitzy)
on CodePen.

Pure CSS Modals

See the Pen
Pure CSS Modals
by Akshay (@akzhy)
on CodePen.

Pure css popup box

See the Pen
Pure css popup box
by Prakash (@imprakash)
on CodePen.

Animated Popup Android Style

See the Pen
Animated Popup Android Style
by Ashwin Saxena (@ashwinsaxena)
on CodePen.

Pop-up design

See the Pen
Pop-up design
by fajjet (@fajjet)
on CodePen.

Pure CSS Modal window / Login & Sign up / Tabs / All Responsive

See the Pen
Pure CSS Modal window / Login & Sign up / Tabs / All Responsive
by Andrew (@AndrewBeznosko)
on CodePen.

Popup Scroll Notification

See the Pen
Popup Scroll Notification
by Zeinab Abounassif (@zeinab92)
on CodePen.

Folding Modal

See the Pen
Folding Modal
by Blake Bowen (@osublake)
on CodePen.

Smart Welcome Popup

See the Pen
Smart Welcome Popup
by CEMR NFT Creator (@sharjeet)
on CodePen.

Push Modal Idea

See the Pen
Push Modal Idea
by Short (@short)
on CodePen.

Colourful Flower Popup Menu

See the Pen
Colourful Flower Popup Menu
by Jasper LaChance (@jasperlachance)
on CodePen.

CSS Modal FAQ

Does ::backdrop inherit styles from the dialog element?

Yes, in current browsers. The ::backdrop pseudo-element inherits from its originating element, so it can read custom properties set on the dialog itself.

Support arrived in Firefox 120, Chrome and Edge 122, and Safari 17.4, according to Chrome for Developers. Older versions needed a :root, ::backdrop selector to share variables.

How does a dialog report which button the user pressed?

Put a form with method=”dialog” inside the dialog. Submitting it closes the dialog without sending data anywhere, and returnValue takes the value of the submitting button.

Read that string in the close event. Calling close(“save”) sets the same property from script.

Can you nest a modal inside another modal?

Technically yes, but avoid it. Calling showModal() on a second dialog stacks it above the first in the top layer, whatever z-index values the page uses.

Bootstrap’s documentation rejects nested modals as a poor user experience, and the a11y-dialog library calls them a questionable pattern outside the spec. Swap the content inside one modal, or open modals in sequence.

What CSS makes a modal full screen?

Reset the browser’s size caps, then fill the viewport. Set max-width: none and max-height: none, then add width: 100%, height: 100% and margin: 0 to the dialog.

Keep a visible close button. A full-screen modal leaves no backdrop to click.

Is a native CSS modal better than a Bootstrap modal?

See the Pen
Material UI popup
by Mikael Ainalem (@ainalem)
on CodePen.

Native wins for new builds, and Bootstrap wins on sites already using it. Bootstrap’s modal runs on HTML, CSS and JavaScript, adds role=”dialog” through script, supports one modal at a time, and ignores the autofocus attribute.

The dialog element supplies top-layer placement and an inert background itself, with no library.

Checks to Run Before Shipping a CSS Modal

A CSS modal ships safely once a keyboard user can open it, leave it and land back on the button that opened it. Test in that order, because the severity of a failure sets the priority.

Keyboard open, close and focus return come first. Scroll lock is next, along with form fields when a phone keyboard is open. The exit animation and the reduced-motion fallback go last.

Combining the W3C dialog pattern with the animation support data gives that sequence. The first group of failures blocks a task, the second disrupts one, and the third costs only polish.

The trade-off is a plain, instant modal on the first release, with motion added after the other checks pass.

As of October 14, 2026, Safari has not shipped closedby, so light dismiss still needs a script there. Revisit that line of the checklist when it does.

A site-wide pass with a web accessibility checklist covers the rest of the page around the modal.

Bogdan Sandu
Latest posts by Bogdan Sandu (see all)