Skip to content
blaze-motion

Preset

stagger

A pair that lands a list one item at a time: staggerParent times the sequence, staggerChild plays each item. The parent animates nothing of its own — it names the hidden and visible variants its children inherit and the step between them. The child carries the opacity and y, and needs a parent above it.

Opacity + transform

  • Copy, do not install
  • One file you own
  • No wrappers
  • Every number in config.ts

Every row starts 16px low and invisible, and each one begins 0.08s after the row above it.

Usage

import { Li, Ul } from "@/lib/motion";
import { staggerChild } from "@/lib/motion/presets/stagger-child";
import { staggerParent } from "@/lib/motion/presets/stagger-parent";

export function Features() {
  return (
    <Ul {...staggerParent} className="grid gap-6 md:grid-cols-3">
      {features.map((feature) => (
        <Li key={feature.title} {...staggerChild}>
          <FeatureCard title={feature.title} />
        </Li>
      ))}
    </Ul>
  );
}

Installation

npx shadcn@latest add https://motion.asmitsah.dev/r/stagger.json

Props and tokens

What it sets

PropertyInitialIn viewReduced motionReads from config.ts
opacity01Animatesfade.from → fade.to
y160Instanttravel.sm → rest.y

Transition and viewport

OptionValueReads from config.ts
staggerChildren0.08staggerStep
duration0.35duration.fast
ease[0.16,1,0.3,1]ease
viewport.oncetrueviewport
viewport.amount"some"viewport
viewport.margin"0px 0px -12% 0px"viewport

Every motion prop the preset does not set — whileHover, whileTap, whileFocus — stays available at the call site. Write it after the spread and it wins.

layout and drag need the domMax feature bundle, not domAnimation — swap the lazy import in provider.tsx. It adds roughly 13kb gzipped on top of domAnimation.