Articles /

New featureanimation

@starting-style: animating element creation

Transition from display: none to visible — entry animations without a single line of JavaScript.

The display: none problem

For years, CSS couldn't animate an element appearing from display: none. The property is discrete — it flips instantly with no intermediate state. The workaround was JavaScript: add a class, wait a frame, then trigger the transition. Or use opacity and pointer-events hacks that leave invisible elements in the tab order. @starting-style fixes this natively.

How @starting-style works

Define a set of starting values that the browser applies on the very first frame an element becomes visible. The browser then transitions from those values to the element's normal state:

.modal {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.3s, transform 0.3s, display 0.3s allow-discrete;

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

/* When hidden, transition out */
.modal[hidden] {
  opacity: 0;
  transform: translateY(1rem);
  display: none;
}

The allow-discrete keyword on the display transition tells the browser to hold display: block during the exit animation, flipping to none only after the transition completes.

Practical use cases

@starting-style is ideal for popovers, dialogs, tooltips, and toast notifications — anything that appears and disappears. Combined with the Popover API (popover attribute), you get fully animated show/hide without JavaScript:

[popover] {
  opacity: 1;
  scale: 1;
  transition: opacity 0.2s, scale 0.2s, display 0.2s allow-discrete, overlay 0.2s allow-discrete;

  @starting-style {
    opacity: 0;
    scale: 0.95;
  }
}

[popover]:not(:popover-open) {
  opacity: 0;
  scale: 0.95;
}

The overlay property

Elements in the top layer (dialogs, popovers) need overlay in the transition list to keep them in the top layer during the exit animation. Without it, the element drops out of the top layer instantly and the exit transition is invisible.

Browser support

@starting-style is supported in Chrome 117+, Safari 17.5+, and Firefox 129+. The allow-discrete keyword and overlay property are part of the same spec. In 2026, this is usable in production with a fallback of no animation for older browsers — the element still shows and hides, it just doesn't animate.

Combine @starting-style with the <dialog> element and the Popover API for fully CSS-driven animated overlays.