Shots in this scene
Variants and Orchestration
In one line
Variants give animation states names. A parent that switches to a named state tells every child to switch to the same name, so one prop drives a whole group, and staggerChildren, delayChildren and when set the order.
Think of it like this
A theatre director calls "Act two". Every actor knows what Act two means for them: the lights change, one walks on, one leaves. The director does not give each actor a script line by line. Variants are those named acts; each component knows what "visible" means for itself.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- variant
- A named animation state, such as
hiddenorvisible, defined once in an object and used by name. - propagation
- A parent's variant name flowing down to children that have variants and no
animateof their own. - staggerChildren
- A transition setting on the parent: each child starts this many seconds after the previous one.
- delayChildren
- A transition setting on the parent: all children wait this long before the first one starts.
- when
"beforeChildren"or"afterChildren": whether the parent's own animation finishes before or after its children's.- orchestration
- Deciding the order and timing of many animations from one place.
Step by step
01Define the states
Write list and item variant objects. item says what hidden and visible look like for one row. list holds only the *transition* that orders its children.
02Switch one prop
The ul has animate={shown ? "visible" : "hidden"}. The li elements have variants={item} and nothing else. Press Hide: the log shows the list, then every item, switching to hidden.
03Read the delays
Press Hide, then look at the tracks: three opacity tracks with delays of 80, 40 and 0 ms (the last item first). Press Show: delays 100, 180 and 260 ms.
04Slow the stagger
Change staggerChildren: 0.08 to 0.3. Show now starts the items at 100, 400 and 700 ms: delay is delayChildren + stagger × index.
Try it yourself
- 1
Slow the stagger
Set
staggerChildren: 0.3and press Hide then Show (or open the Timeline after Show). Measured: the three opacity tracks start at 100, 400 and 700 ms. - 2
Mistype a variant name
Change
"visible"to"visibl"in theanimateprop. The console still printslist starts: visibl, but at 400 ms the first item is at opacity 0 and 24 px left (measured): nothing animates.
Code & diagrams
The ul switches state and every li follows. Hide runs last-to-first, Show first-to-last. The console lists who starts in what order.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
list starts: visible
Lock starts: visible
Lights starts: visible
Bell starts: visibleA inherits "on". B's string `animate` keeps it out of the group. C's object `animate` does not: it also gets "on", and ends at opacity 1.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
B (own animate): "off"
C (an object): {"opacity":0.7}
A (inherits): "on"
C (an object): "on"Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Give a child an object animate
In the second example, add animate={{ opacity: 0.7 }} to item A.
Myth vs fact
Myth
Children need initial and animate to follow the parent.
Fact
They need only variants with matching names. Adding their own animate string opts them out.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
On the Timeline, a spring's
delayis folded into itslinear()curve: with delays of 80, 40 and 0 ms, the three transform tracks last 430, 390 and 350 ms and all showdelay 0. Read the opacity tracks for the real delays. - ▸
custompasses data into variant functions:visible: (i) => ({ opacity: 1, transition: { delay: i * 0.05 } })withcustom={i}on each child. Use it when the delay depends on something other than DOM order. Motion 14 also exports astagger()function fordelayChildrenand for vanillaanimate(). - ▸
Stagger totals grow with the list. A staggered entrance for a long list should be capped (about 0.5 s in total) or only applied to the first screenful.
Remember this
- 1
The problem this solves: a menu of six items must appear one after another. With plain
animateprops you pass the state down six times and compute six delays by hand, and the delays go wrong the day a seventh item appears. Variants move that bookkeeping out of your components. - 2
Named states. A variants object maps names to targets:
{ hidden: { opacity: 0, x: -24 }, visible: { opacity: 1, x: 0 } }. Pass it asvariants, then use the names ininitialandanimate:animate="visible". The name can also come from state, as inanimate={shown ? "visible" : "hidden"}. - 3
Propagation. When a parent's
animateis a variant name, children that havevariantsbut noanimateof their own receive the same name. They need not mentioninitialoranimateat all. The example below logs the order Motion starts them: the list first, then Lock, Lights and Bell. - 4
Orchestration. Put
transitioninside the *parent's* variant.staggerChildren: 0.08starts each child 0.08 s after the previous;delayChildren: 0.1delays them all;staggerDirection: -1runs the last child first.when: "beforeChildren"finishes the parent's own animation first, and"afterChildren"waits for the children. Measured on the Timeline: withdelayChildren: 0.1andstaggerChildren: 0.08, the three opacity tracks start at 100, 180 and 260 ms; hiding with-1and 0.04 gives 80, 40 and 0. - 5
**A child with its own
animate.** A stringanimateon a child opts it out of propagation: item B below keeps its own label and stays at opacity 0.3. An object does not: item C asks for{ opacity: 0.7 }and still receives the parent's"on"afterwards, and ends at 1 (measured, in the order the log shows). If a child must stay out of a group, give it a variant label of its own. - 6
Edge cases. A name that no variant defines is not an error: with
animate="visibl"(a typo) the list logs the start but nothing moves, and the items stay hidden (measured). An empty list has no children to wait for. For long lists the delay adds up: 100 items at 0.08 s means the last starts after 8 s. Cap the total:staggerChildren: Math.min(0.08, 0.5 / n)keeps a 100-item entrance near half a second.
Explain it without notes
How does a parent control children without props reaching them?
What do staggerChildren, delayChildren and when each do, and where do they go?
Practice
Make a card whose title, text and button slide up one after another when the card appears, 0.1 s apart, after the card itself has faded in.
A list can have 5 or 500 rows. Write the variant so the whole stagger takes at most 0.6 s.
Done when you can
You can define variants and switch a group with one
animatepropYou can place
staggerChildren,delayChildrenandwhenand read their effect on the TimelineYou can say which kind of child
animateleaves a group and which does notYou can cap a stagger so a long list stays quick