Exit Animations Chris Coyier

Publish date: 2024-03-19

How do you animate an element as it leaves the DOM?

You can’t, is the historical answer. As soon as an element is removed from the DOM, it immediately disappears, there is no animation opportunity. The trick is to animate it as if it is leaving, wait for the animation is finished, then actually remove it from the DOM.

Element.classList.add("do-outgoing-animation"); setTimeout(() => { Element.remove(); }, SAME_TIMING_AS_ANIMATION_IN_CSS);Code language: CSS (css)

You could also wait for an animationend event or whatever. That’s awkward and error-prone, at a minimum. Plus, if you’re using a JavaScript framework, you aren’t really in charge of when that element gets removed from the DOM, that happens somewhere in the bowels of the framework, so doing this will have a different approach in all of them.

View Transitions have opened up a bit of a door here, because of how they animate a rasterized version of the element. That means theoretically the element can be removed from the DOM immediately but we could still do an animation. It does actually work:

Element.style.viewTransitionName = "unique-outgoing-ident"; Element.remove();Code language: JavaScript (javascript)
::view-transition-old(unique-outgoing-ident) { animation: outgoing 1s; }Code language: CSS (css)

I don’t find this terribly elegant either. Every outgoing element needs a unique identifier otherwise the animation breaks. That’s just an annoying feature of an API where it’s highly likely you’re essentially just applying the same animation.

Jessica Janiuk has proposed Exit animations (@exit-style). Which I’m liking so far. It pairs up with @starting-style which is also super useful for essentially the same reason in reverse.

.posts { > li { transition: .4s opacity; @exit-style { opacity: 0; } } }Code language: CSS (css)

I really like how you don’t need to name anything there. Very elegant pairing with an existing API and CSS nesting.

There is also the extremely bizarrely named transition-behavior: allow-discrete which is a smidge of prior art here. You could use this is, for example, rather than removing an element from the DOM, you set display: none. Previously, the display property wasn’t really “animatable” because it would “flip” to the new value immediately in an animation/transition. So this new behavior-setter allows it to flip at the end instead. Useful, but it doesn’t help with DOM removal.

Annnnyway, I hope @exit-style or @exiting-style or @outgoing-style or ::outgoing or something hits CSS eventually, that’d be cool.

ncG1vNJzZmibmKe2tK%2FOsqCeql6jsrV7kWlpbGdhZXx0fI6er6KsXZa7qrnAraCopqNk