Animation Orchestration — variants · stagger · AnimatePresence

[check: …]
📖 guide (.md) ← react deep dive
📖 Pair this live React playground with the companion guide (.md) — this page is the rendered ground truth. ↗ framer_motion_core covers single-element animation (the rAF tween loop) — orchestration coordinates MULTIPLE elements on top of it.

one element → many elements: the three primitives

framer_motion_core animates a single element with a requestAnimationFrame tween. Real UIs need choreography: a list ripples in one-by-one, a dismissed card fades out before it leaves the DOM, a parent flips a label and every child follows. Framer Motion ships three primitives for this — and each is a plain-React mechanism in disguise:

primitivewhat it doesthe plain-React mechanism (used here)
variants named target objects (hidden, visible, exit) — parent switches the label, children inherit it a React.Context carries the active label + stagger step down the tree
stagger children animate with a sequential delay — a wave, not a flash each child reads its index and sets transitionDelay = index * step
AnimatePresence keeps a removed child mounted long enough to play its exit animation park the id in an "exiting" map, render it with the exit target, splice after N ms

The demo below implements all three from scratch — no motion/react import. Items enter with a stagger, the list label flips hidden → visible on mount, and the Remove button parks the row in an exit state for 300ms before the real unmount.

1 · the orchestrator you write (edit me)

2 · Babel compiles JSX → element tree

<VariantContext.Provider> becomes React.createElement(VariantContext.Provider, …). The Context value flows down; each MotionItem reads it via useContext and computes its own delay.

// (hit "compile & render" to see Babel's output)

3 · live React (variants + stagger + exit, proven)

On mount the list label flips hidden → visible and items ripple in with a 0.08s stagger. Click Add to append; click to remove — the row slides out over 300ms, THEN unmounts. The gold-check automates this: assert 3 → add → assert 4 → remove #1 → wait for exit → assert 3 remain and #1 is gone.

items: · gold: 3 → +Add → 4 → remove #1 → wait exit → 3 remain, #1 gone

intent → orchestration primitive

intentprimitivewhy
parent flips a label, children follow variants + a Context one switch animates N children — no per-child prop drilling
list ripples in one-by-one staggerChildren / per-index transitionDelay wave effect; each child waits index * step
removed element animates out first AnimatePresence / defer unmount React unmounts instantly; you must hold the node for the exit duration
pause before children start delayChildren (no stagger) all children wait ONE delay, then animate together
parent finishes before children start when: 'beforeChildren' strict ordering — parent then children, not overlapping
different timing per variant transition inside each variant target visible can spring, exit can tween — independent