GSAP in Webflow · Concepts

Stagger — spreading one animation across many targets

Stagger spreads a single animation across multiple targets, so it does nothing at all with one target; offset time sets a fixed gap between each target's start while total time is one budget divided across the intervals, and the stagger's own ease shapes the distribution of delays — a different job from the action's ease.

  • intermediate
  • Last verified: July 27, 2026
  • Verified against: author, lesson-prose

The rule

Stagger needs several targets or it does nothing. With a single element there is nothing to spread, so turning it on looks identical to leaving it off. If a lone h1 isn’t staggering, the fix is Split Text — turning one text element into many targets — break it into words or letters so each piece becomes a target.

Two ways to time it, and they answer opposite questions:

MeaningAs the count grows
Offset timeA fixed delay between each target’s startThe sequence gets longer
Total timeOne budget for the whole stagger, divided across the intervalsEach gap gets smaller

The number of intervals is always targets − 1. So 13 letters with a total time of 0.5s gives gaps of 0.5 ÷ 12 ≈ 0.04s — tight and smooth.

Use total time when the reveal must fit a known slot on the timeline. Use offset time when the rhythm between pieces matters more than the overall length.

How and why

The from origin changes order only. start, center, end, edges, random, element decide where the sequence beginscenter animates the middle piece first then works outward, edges fires the outer pieces first and moves inward. The spacing maths between pieces is identical in every case. It costs nothing and completely changes the personality of the animation, so it is the first thing to try when a reveal feels generic.

There are two easings and they are not the same thing. This trips up almost everyone, because they share a name and sit two panels apart.

EaseShapes
The action’s easeHow each individual piece travels from its start value to its end value
The stagger’s easeThe distribution of the delays between pieces

Leave the stagger ease at none and the gaps are even. A curve ending in in packs the gaps tight then spreads them — the reveal feels like it is slowing down. One ending in out spreads then tightens — it feels like it is speeding up. Exotic curves (back, bounce, elastic) produce deliberately chaotic spacing: fun, rarely right for a heading.

Tuning tip: exaggerate the total time while you choose a stagger ease so you can actually see what the curve does, then dial it back.

When GSAP’s stagger is the wrong tool

Per-row stagger on scroll cannot be done with it, and this is worth knowing before you waste an hour. Neither target works:

  • Target the trigger element → each card animates alone; a single element has no siblings to stagger against.
  • Target the shared attribute → the first time it fires, GSAP staggers the entire collection at once, including cards far below the fold.

The pattern that does work inverts the responsibility: GSAP does the minimum — a set action adding an in-view class to each card as it enters the viewport — and the animation lives in CSS transitions between the initial state and the in-view state. The stagger is then a per-card transition-delay, computed from the card’s position within its row using the sibling-index() CSS function and a Webflow variable for the column count. Give that variable a mode per breakpoint (e.g. 3 / 3 / 2 / 1) and the delays re-derive correctly whenever the grid reflows — responsive with no rebuild.

Two consequences worth carrying: the initial state hides the cards in the Designer too, so add an override that forces them visible when Webflow’s JS class is absent on html (true only inside the Designer); and this approach works identically for static elements, not just CMS lists.

The attribute-driven script variant

A no-code cloneable exposes stagger through custom attributes instead of the panel, and its vocabulary is GSAP’s own rather than Webflow’s. Only the marker is prefixed; every option is a bare attribute name.

AttributePanel equivalentValue
fc-gsap-staggeredlist — the one required attribute
threshold— visibility fraction at which it fires0.4
eachoffset time — fixed gap in seconds0.2
amounttotal time — split across the row0.5
durationhow long one item’s animation lasts0.5
offset-yinitial vertical offset each item slides up from3rem
fromthe stagger’s from origin (also accepts a zero-based index)start
easethe action’s easepower3.out
staggered-easethe stagger’s ease — distributes the delayspower1.out

each and amount conflict by design: if amount is set, each is ignored even when it holds a valid value. This is the single most common misconfiguration, and it means at most one of those two rows applies to any given build.

fc-gsap-staggered="list" goes on the div wrapping your items, or straight onto a Collection List; that alone gives the default animation. Multiple lists on one page need no indexes to tell them apart, and the same attribute works on static layouts, CMS collections and custom grids alike.

Two names to get right, because both fail silently:

  • offset-y, not offsetY. HTML attribute names are lower-cased by the parser, so a camelCase spelling becomes offsety and never matches. The lesson prose has this wrong; the cloneable is authoritative.
  • staggered-ease is a separate attribute from ease. They are the two easings from the section above — one shapes each item’s motion, one shapes the distribution of delays.

Interaction repeat, not stagger, loops a sequence

A staggered reveal that should cycle forever loops at the interaction level so all its actions stay in sync. Staggering and looping are independent settings — see Timeline control — control, speed, jump to, delay, repeat.

Sources