CSS transition-behavior: allow-discrete for Dialogs
The CSS transition-behavior: allow-discrete property
enables animations and transitions on discrete CSS properties—such as
display and overlay—that traditionally could
not be transitioned. In HTML <dialog> animations,
this property ensures that a dialog remains visible in the DOM during
its closing animation, allowing smooth exit transitions before switching
to display: none, without needing complex JavaScript
timeouts or event listeners.
The Problem with Dialog Exit Animations
By default, the native HTML <dialog> element
toggles between display: block when open and
display: none when closed. Properties with discrete values
do not have intermediate states for CSS to interpolate.
When a user closes a dialog, the browser immediately applies
display: none. Even if you define an exit transition on
properties like opacity or transform, the
abrupt switch to display: none hides the element instantly,
cutting off any exit animations before they can play.
How allow-discrete Solves the Issue
The transition-behavior property accepts two values:
normal (the default) and allow-discrete.
When set to allow-discrete, the browser alters how it
handles the transition of discrete properties:
- On entry: The property (such as
display) switches immediately to its visible state at0%of the transition duration so the element is rendered and can animate into view. - On exit: The property delays switching to its
hidden state (
display: none) until the entire transition duration has finished.
This allows accompanying transition effects, such as fading out or scaling down, to play to completion while the dialog remains rendered.
Key Companion Features
To make full use of transition-behavior: allow-discrete
for <dialog> animations, it is typically paired with
two other modern CSS capabilities:
@starting-style: Defines the initial visual state of the dialog before it opens, enabling smooth entry transitions fromdisplay: none.- The
overlayproperty: Manages the top layer transition, ensuring the dialog does not prematurely drop out of the browser's top layer before the exit animation finishes.
Implementation Example
You can apply transition-behavior: allow-discrete
individually to specific properties using the longhand syntax or inline
within the transition shorthand.
dialog {
opacity: 0;
transform: scale(0.9);
/* Shorthand declaration: transition property, duration, timing, behavior */
transition:
opacity 0.3s ease-out,
transform 0.3s ease-out,
overlay 0.3s ease-out allow-discrete,
display 0.3s ease-out allow-discrete;
}
/* Open state */
dialog[open] {
opacity: 1;
transform: scale(1);
}
/* Entry starting style */
@starting-style {
dialog[open] {
opacity: 0;
transform: scale(0.9);
}
}In this setup, when dialog.close() is called or the
open attribute is removed, display and
overlay wait the specified 0.3s before
changing, giving the opacity and transform
properties the time required to complete their exit transitions.