DocsJavaScriptMotion reference

stagger

stagger() distributes a delay across elements, with control over origin and easing.

Stagger animations delay each element in a sequence by a set amount of time, creating a cascading or wave-like effect. Motion's stagger() function makes this easy.

It's perfect for animating lists, grids, navigation menus and loading icons. Its also the key feature in split text animations, where staggering the characters is the whole effect: the text animation guide explains more.

import { animate, stagger } from "motion"

animate(
  "li",
  { opacity: 1 },
  { delay: stagger(0.1) }
)
Live exampleOpen

Usage

Import stagger from Motion.

import { animate, stagger } from "motion"

By passing a duration, in seconds, to stagger, the delay of each element will be increased by that amount for each animation.

animate(
  "li",
  { opacity: 1 },
  { delay: stagger(0.1) }
)

Animation sequencing

It's also possible to stagger segments within animation sequences.

animate([
  ["ul", { opacity: 1 }]
  ["li", { x: [100, 0] }, { delay: stagger(0.05) }]
])

Any subsequent segments will be scheduled after the final staggered element.

Negative staggers

Motion supports setting delay as a negative value in order to start an animation mid-way.

animate(
  element,
  keyframes,
  // Will start half-way through the animation
  { delay: -1, duration: 2 }
)

This means you can also set stagger to a negative offset to start animations at staggered mid-points.

delay: stagger(0.05, { startDelay: -1 })

For instance, this loading spinner tutorial explains how, by setting startDelay to a negative value, all of the icon segments can start mid-animation rather than waiting for a full iteration before they're all animating together.

Live exampleOpen

Grid stagger

The stagger function doesn't yet support staggered grids, but this physically-aware stagger tutorial explains how this can be calculated dynamically.

Live exampleOpen

Stagger direction

It's possible to set a stagger direction by choosing a direction to stagger from. The from option can be set as "first", "center", "last", or any item index.

Live exampleOpen

Stagger React animations

stagger works with Motion for React via a variant's delayChildren option.

const parentVariants = {
  open: {
    opacity: 1,
    transition: {
      delayChildren: stagger(0.1)
    }
  },
  close: {
    opacity: 0,
    transition: {
      delayChildren: stagger(0.01, { from: "last" })
    }
  }
}

By setting delayChildren to stagger, when children enter the defined variant they'll be delayed by the defined amount of time.

<motion.ul animate={isOpen ? "open" : "closed"} variants={parentVariants}>
  <motion.li variants={childVariants} />
</motion.ul>

Options

stagger accepts options via its second argument.

startDelay

Default: 0

The initial delay from which to calculate subsequent delays.

stagger(0.1, { startDelay: 0.2 }) // 0.2, 0.3, 0.4...

from

Default: "first"

Specifies which element in the array from which to stagger. Can be set as "first", "center", "last", or a number to specify an index.

stagger(0.05, { from: "last" })
Live exampleOpen

ease

Default: "linear"

By passing an easing function, staggers can be redistributed through the total stagger time.

Any easing function or Motion easing is accepted, like a cubic bezier definition:

stagger(0.1, { ease: [.32, .23, .4, .9] })

Name of an easing function:

stagger(0.1, { ease: "easeOut" })

Or a custom easing function:

stagger(0.1, { ease: p => Math.sin(p) })

FAQs

What is a stagger animation?

A stagger animation delays each element in a group by a fixed amount, creating a cascading, wave, or ripple effect.

How do I stagger from a different origin?

Use the from option: stagger(0.1, { from: "center" }).

Is it possible to stagger in React or Vue?

Yes. You can use stagger with useAnimate, and it's possible to also pass it straight to delayChildren when animating with variants.

How do I create a wave effect with stagger?

Combine stagger with easing functions to adjust the speed throughout the animation.