stagger

Stagger is a GSAP property that offsets the start time of each target in a tween, animating them one after another instead of all at once. It's the single most-used tool for making a list, grid, or sequence of elements feel choreographed rather than mechanical.

Ships in
GSAP core
Used in
5 Annnimate components

Updated June 1, 2026

Pick an underlined value to change it

gsap.to(".box", {
y: -34,
stagger: ,
repeat: 1,
yoyo: true,
});

How stagger works

The simplest form is a number - the delay in seconds between each target's start time:

script.js

For 10 items at stagger: 0.08, the first item starts at t=0, the last at t=0.72, and the whole sequence finishes at t=0.72 + 0.6 = 1.32s.

The richer config

script.js

The two eases compose: ease: "expo.out" is the per-element animation curve, stagger.ease is how the START TIMES distribute across the set. A power2.in stagger ease makes early items cluster close together and later items spread out - useful for 'spilling outward' effects.

Use stagger for

  • Reveal animations on lists, cards, or grids
  • Character-by-character text reveals (paired with SplitText)
  • Grid-of-tiles entrance animations
  • Sequencing logo paths or SVG elements
  • Anywhere 'one after another' reads better than 'all at once'

Use something else when

  • Single elements - just don't pass stagger
  • True asynchronous sequencing - use a GSAP timeline with explicit position parameters per tween
  • Physics-based delays - stagger is deterministic; for true randomness use from: "random" or compute delays per-target

Used in these Annnimate components

Common questions

What's the difference between stagger.each and stagger.amount?
each is the delay between each target's start (in seconds). amount is the total time the staggered set should span - GSAP calculates each automatically as amount / count. Use each when you want a fixed rhythm regardless of count; use amount when you want the total animation length to stay constant as the count changes.
How do stagger.from values like 'start', 'center', 'edges' work?
They define WHICH target gets index 0 - the one that starts first. start (default): first child first. end: last child first. center: middle child first, rippling outward. edges: first and last simultaneously, rippling inward. random: shuffled order. For grids, you also have from: [0.5, 0.5] which uses normalized 2D coordinates to pick a focal point.
Why isn't my grid stagger respecting the rows/columns?
You need to pass stagger: { grid: [rows, cols], ... }. Without grid, GSAP treats the targets as a 1D list and staggers in DOM order. With grid: [3, 4], GSAP knows the layout and can stagger by distance from a focal point (from: 'center') instead of by index.
Can I combine stagger with a position parameter on a timeline?
Yes. The position parameter ('<', '>', '+=0.5') decides WHEN the staggered batch starts; the stagger itself controls the rhythm within. Common pattern: tl.to(items, { ... stagger: 0.05 }, 'reveal') to fire all staggered items together with another tween labeled 'reveal'.