@starting-style / allow-discrete
Native Show/Hide Transitions
Transitioning something into existence used to mean never actually setting display: none, keeping it in the layout at opacity: 0 and pointer-events: none instead, plus a bit of JS to add display: none after the fact. @starting-style and transition-behavior: allow-discrete let display itself be the toggle, animated both ways.
Booster separation confirmed. No JS animation library involved.
The CSS
.toast {
display: none;
opacity: 0;
transform: translateY(14px);
transition:
opacity 0.25s ease,
transform 0.25s ease,
display 0.25s allow-discrete;
&[data-open='true'] {
display: flex;
opacity: 1;
transform: translateY(0);
/* the "before" frame for the entry transition */
@starting-style {
opacity: 0;
transform: translateY(14px);
}
}
}How it works
The toast never unmounts, a data-open attribute just flips its display between none and flex. Normally a transition can’t animate across a display change at all (there’s no box to animate from once it’s none), but listing display in the transition property with allow-discrete tells the browser to hold the old value for the outgoing frame, and the new one for the incoming frame, instead of snapping instantly.
@starting-style fills in the other half: the styles an element should transition from the moment it first becomes visible, since an element that was just display: none has no previous frame to animate from otherwise.
Chrome / Edge 117+, Safari 17.5+, Firefox 129+