Docs
Next

Animation timing

animate-delay-*, animate-duration-*, animate-ease-*, stagger-* and stagger-delay-*.

On this page

The timing utilities tune the fade animations: animate-delay-*, animate-duration-* and animate-ease-* set one element's delay, duration and curve, and stagger-* with stagger-delay-* delay siblings one after another so a row of cards cascades instead of appearing at once.

Quick referenceLink to this section

Delay, duration and easing for one element. The ease-* classes at the end are the matching curves for CSS transitions:

ClassStyles
animate-delayanimation-delay: 150ms;
animate-delay-0animation-delay: 0s;
animate-delay-75animation-delay: 75ms;
animate-delay-100animation-delay: 100ms;
animate-delay-150animation-delay: 150ms;
animate-delay-200animation-delay: 200ms;
animate-delay-300animation-delay: 300ms;
animate-delay-500animation-delay: 500ms;
animate-delay-700animation-delay: 700ms;
animate-delay-1000animation-delay: 1000ms;
animate-durationanimation-duration: 150ms;
animate-duration-0animation-duration: 0s;
animate-duration-75animation-duration: 75ms;
animate-duration-100animation-duration: 100ms;
animate-duration-150animation-duration: 150ms;
animate-duration-200animation-duration: 200ms;
animate-duration-300animation-duration: 300ms;
animate-duration-500animation-duration: 500ms;
animate-duration-700animation-duration: 700ms;
animate-duration-1000animation-duration: 1000ms;
animate-easeanimation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
animate-ease-inanimation-timing-function: cubic-bezier(0.4, 0, 1, 1);
animate-ease-in-backanimation-timing-function: cubic-bezier(0.36, 0, 0.66, -0.56);
animate-ease-in-circanimation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
animate-ease-in-cubicanimation-timing-function: cubic-bezier(0.32, 0, 0.67, 0);
animate-ease-in-expoanimation-timing-function: cubic-bezier(0.7, 0, 0.84, 0);
animate-ease-in-outanimation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
animate-ease-in-out-backanimation-timing-function: cubic-bezier(0.68, -0.6, 0.32, 1.6);
animate-ease-in-out-circanimation-timing-function: cubic-bezier(0.85, 0, 0.15, 1);
animate-ease-in-out-cubicanimation-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
animate-ease-in-out-expoanimation-timing-function: cubic-bezier(0.87, 0, 0.13, 1);
animate-ease-in-out-quadanimation-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
animate-ease-in-out-quartanimation-timing-function: cubic-bezier(0.76, 0, 0.24, 1);
animate-ease-in-out-quintanimation-timing-function: cubic-bezier(0.83, 0, 0.17, 1);
animate-ease-in-out-sineanimation-timing-function: cubic-bezier(0.37, 0, 0.63, 1);
animate-ease-in-quadanimation-timing-function: cubic-bezier(0.11, 0, 0.5, 0);
animate-ease-in-quartanimation-timing-function: cubic-bezier(0.5, 0, 0.75, 0);
animate-ease-in-quintanimation-timing-function: cubic-bezier(0.64, 0, 0.78, 0);
animate-ease-in-sineanimation-timing-function: cubic-bezier(0.12, 0, 0.39, 0);
animate-ease-linearanimation-timing-function: linear;
animate-ease-outanimation-timing-function: cubic-bezier(0, 0, 0.2, 1);
animate-ease-out-backanimation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
animate-ease-out-circanimation-timing-function: cubic-bezier(0, 0.55, 0.45, 1);
animate-ease-out-cubicanimation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
animate-ease-out-expoanimation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
animate-ease-out-quadanimation-timing-function: cubic-bezier(0.5, 1, 0.89, 1);
animate-ease-out-quartanimation-timing-function: cubic-bezier(0.25, 1, 0.5, 1);
animate-ease-out-quintanimation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
animate-ease-out-sineanimation-timing-function: cubic-bezier(0.61, 1, 0.88, 1);
ease-in-back--tw-ease: cubic-bezier(0.36, 0, 0.66, -0.56);transition-timing-function: cubic-bezier(0.36, 0, 0.66, -0.56);
ease-in-circ--tw-ease: cubic-bezier(0.55, 0, 1, 0.45);transition-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
ease-in-cubic--tw-ease: cubic-bezier(0.32, 0, 0.67, 0);transition-timing-function: cubic-bezier(0.32, 0, 0.67, 0);
ease-in-expo--tw-ease: cubic-bezier(0.7, 0, 0.84, 0);transition-timing-function: cubic-bezier(0.7, 0, 0.84, 0);
ease-in-out-back--tw-ease: cubic-bezier(0.68, -0.6, 0.32, 1.6);transition-timing-function: cubic-bezier(0.68, -0.6, 0.32, 1.6);
ease-in-out-circ--tw-ease: cubic-bezier(0.85, 0, 0.15, 1);transition-timing-function: cubic-bezier(0.85, 0, 0.15, 1);
ease-in-out-cubic--tw-ease: cubic-bezier(0.65, 0, 0.35, 1);transition-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
ease-in-out-expo--tw-ease: cubic-bezier(0.87, 0, 0.13, 1);transition-timing-function: cubic-bezier(0.87, 0, 0.13, 1);
ease-in-out-quad--tw-ease: cubic-bezier(0.45, 0, 0.55, 1);transition-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
ease-in-out-quart--tw-ease: cubic-bezier(0.76, 0, 0.24, 1);transition-timing-function: cubic-bezier(0.76, 0, 0.24, 1);
ease-in-out-quint--tw-ease: cubic-bezier(0.83, 0, 0.17, 1);transition-timing-function: cubic-bezier(0.83, 0, 0.17, 1);
ease-in-out-sine--tw-ease: cubic-bezier(0.37, 0, 0.63, 1);transition-timing-function: cubic-bezier(0.37, 0, 0.63, 1);
ease-in-quad--tw-ease: cubic-bezier(0.11, 0, 0.5, 0);transition-timing-function: cubic-bezier(0.11, 0, 0.5, 0);
ease-in-quart--tw-ease: cubic-bezier(0.5, 0, 0.75, 0);transition-timing-function: cubic-bezier(0.5, 0, 0.75, 0);
ease-in-quint--tw-ease: cubic-bezier(0.64, 0, 0.78, 0);transition-timing-function: cubic-bezier(0.64, 0, 0.78, 0);
ease-in-sine--tw-ease: cubic-bezier(0.12, 0, 0.39, 0);transition-timing-function: cubic-bezier(0.12, 0, 0.39, 0);
ease-out-back--tw-ease: cubic-bezier(0.34, 1.56, 0.64, 1);transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
ease-out-circ--tw-ease: cubic-bezier(0, 0.55, 0.45, 1);transition-timing-function: cubic-bezier(0, 0.55, 0.45, 1);
ease-out-cubic--tw-ease: cubic-bezier(0.33, 1, 0.68, 1);transition-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
ease-out-expo--tw-ease: cubic-bezier(0.16, 1, 0.3, 1);transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
ease-out-quad--tw-ease: cubic-bezier(0.5, 1, 0.89, 1);transition-timing-function: cubic-bezier(0.5, 1, 0.89, 1);
ease-out-quart--tw-ease: cubic-bezier(0.25, 1, 0.5, 1);transition-timing-function: cubic-bezier(0.25, 1, 0.5, 1);
ease-out-quint--tw-ease: cubic-bezier(0.22, 1, 0.36, 1);transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
ease-out-sine--tw-ease: cubic-bezier(0.61, 1, 0.88, 1);transition-timing-function: cubic-bezier(0.61, 1, 0.88, 1);

Stagger, applied to each sibling:

ClassStyles
stagger&:nth-child(1n) { animation-delay: 0ms; }&:nth-child(1n - 0) { animation-delay: 0ms; }
stagger-1&:nth-child(1n) { animation-delay: 0ms; }&:nth-child(1n - 0) { animation-delay: 0ms; }
stagger-2&:nth-child(2n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 1); }&:nth-child(2n - 1) { animation-delay: 0ms; }
stagger-3&:nth-child(3n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 2); }&:nth-child(3n - 1) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 1); }&:nth-child(3n - 2) { animation-delay: 0ms; }
stagger-4&:nth-child(4n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 3); }&:nth-child(4n - 1) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 2); }&:nth-child(4n - 2) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 1); }&:nth-child(4n - 3) { animation-delay: 0ms; }
stagger-5&:nth-child(5n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 4); }&:nth-child(5n - 1) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 3); }&:nth-child(5n - 2) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 2); }&:nth-child(5n - 3) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 1); }&:nth-child(5n - 4) { animation-delay: 0ms; }
stagger-6&:nth-child(6n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 5); }&:nth-child(6n - 1) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 4); }&:nth-child(6n - 2) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 3); }&:nth-child(6n - 3) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 2); }&:nth-child(6n - 4) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 1); }&:nth-child(6n - 5) { animation-delay: 0ms; }
stagger-7&:nth-child(7n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 6); }&:nth-child(7n - 1) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 5); }&:nth-child(7n - 2) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 4); }&:nth-child(7n - 3) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 3); }&:nth-child(7n - 4) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 2); }+ 2 more rules
stagger-8&:nth-child(8n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 7); }&:nth-child(8n - 1) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 6); }&:nth-child(8n - 2) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 5); }&:nth-child(8n - 3) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 4); }&:nth-child(8n - 4) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 3); }+ 3 more rules
stagger-9&:nth-child(9n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 8); }&:nth-child(9n - 1) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 7); }&:nth-child(9n - 2) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 6); }&:nth-child(9n - 3) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 5); }&:nth-child(9n - 4) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 4); }+ 4 more rules
stagger-10&:nth-child(10n) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 9); }&:nth-child(10n - 1) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 8); }&:nth-child(10n - 2) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 7); }&:nth-child(10n - 3) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 6); }&:nth-child(10n - 4) { animation-delay: calc(var(--tw-stagger-delay, 300ms) * 5); }+ 5 more rules
stagger-delay--tw-stagger-delay: 150ms;
stagger-delay-0--tw-stagger-delay: 0s;
stagger-delay-75--tw-stagger-delay: 75ms;
stagger-delay-100--tw-stagger-delay: 100ms;
stagger-delay-150--tw-stagger-delay: 150ms;
stagger-delay-200--tw-stagger-delay: 200ms;
stagger-delay-300--tw-stagger-delay: 300ms;
stagger-delay-500--tw-stagger-delay: 500ms;
stagger-delay-700--tw-stagger-delay: 700ms;
stagger-delay-1000--tw-stagger-delay: 1000ms;

Basic usageLink to this section

Combine a fade with a delay and a duration. The fades default to one second with ease-out-cubic; the timing classes override one part each. Press Replay to compare:

Delay and duration
import { useState } from 'react'
import { Button } from '@systhemaui/next'

export default function Demo() {
  const [run, setRun] = useState(0)

  return (
    <div className="flex w-full flex-col items-center gap-6">
      <div key={run} className="flex w-full flex-col gap-3 overflow-hidden">
        <Bar className="animate-fadeinleft">animate-fadeinleft</Bar>
        <Bar className="animate-fadeinleft animate-delay-300">animate-delay-300</Bar>
        <Bar className="animate-fadeinleft animate-delay-700">animate-delay-700</Bar>
        <Bar className="animate-fadeinleft animate-duration-300">animate-duration-300</Bar>
        <Bar className="animate-fadeinleft animate-ease-in-out-back">animate-ease-in-out-back</Bar>
      </div>
      <Button.button variant="secondary" onClick={() => setRun(run + 1)}>
        Replay
      </Button.button>
    </div>
  )
}

function Bar({ className, children }: { className: string; children: string }) {
  return (
    <div
      className={`rounded-md bg-(--color-foundations-primary-bg) px-4 py-2 text-small text-(--color-foundations-primary-text) ${className}`}
    >
      {children}
    </div>
  )
}
<p class="aos animate-fadeinup animate-delay-300 animate-duration-700">…</p>

Delays and durations use Tailwind's duration scale (0, 75, 100, 150, 200, 300, 500, 700 and 1000 ms; the bare animate-delay and animate-duration are 150ms), and both accept arbitrary values: animate-delay-[1.2s]. The animate-ease-* names are the curves on Easing and transitions.

StaggerLink to this section

stagger-<n> goes on every sibling, where n is how many items share a row. Each item gets a delay from its position in that row: the first none, the second one step, the third two steps, and the count starts over on the next row. One step is var(--tw-stagger-delay, 300ms); set it with stagger-delay-* on the items or, because the custom property inherits, once on their parent.

Staggered reveal
import { useState } from 'react'
import { Button } from '@systhemaui/next'

const items = ['Plan', 'Design', 'Build', 'Launch', 'Measure', 'Improve']

export default function Demo() {
  const [run, setRun] = useState(0)

  return (
    <div className="flex w-full flex-col items-center gap-6">
      <div key={run} className="grid w-full grid-cols-3 gap-3 stagger-delay-150">
        {items.map((item) => (
          <div
            key={item}
            className="aos animate-fadeinup stagger-3 flex h-24 items-center justify-center rounded-lg border border-(--color-foundations-surface-border) bg-(--color-foundations-surface-bg) color-heading"
          >
            {item}
          </div>
        ))}
      </div>
      <Button.button variant="secondary" onClick={() => setRun(run + 1)}>
        Replay
      </Button.button>
    </div>
  )
}
<div class="grid grid-cols-3 gap-3 stagger-delay-150">
  <div class="aos animate-fadeinup stagger-3">Plan</div>
  <div class="aos animate-fadeinup stagger-3">Design</div>
  <div class="aos animate-fadeinup stagger-3">Build</div>
  <!-- the next three start over at no delay -->
</div>
  • stagger-1 to stagger-10 are generated; stagger alone is stagger-1, which means no delay.
  • The delay comes from :nth-child, so the items must be siblings in one parent, and other children in that parent count too.
  • Each item still reveals when it scrolls in. In a grid every row enters the viewport together, so the row cascades from left to right.

The Posts listing staggers its cards per grid column with the same --tw-stagger-delay custom property, using a shorter 120ms default, so one stagger-delay-* class retunes both.

Responsive and state variantsLink to this section

Every timing class takes breakpoint prefixes. Match the stagger count to the column count at each size:

<div class="aos animate-fadeinup stagger-1 md:stagger-2 lg:stagger-3">…</div>

With grid-cols-1 md:grid-cols-2 lg:grid-cols-3, that cascades the two-up rows on tablets and the three-up rows on desktops, and plays phone items one by one as they scroll in.

Reduced motionLink to this section

Under prefers-reduced-motion: reduce the fades snap to their end state, so delays, durations and stagger have nothing to time: content appears at once. See Accessibility utilities.

CustomizingLink to this section

The delay, duration and stagger-step scales reuse Tailwind's transition-duration scale, and the easing names come from the Systhema easing table, which a project's easings token collection can override curve by curve (see Motion tokens and the motion reference). For a value outside the scales, use an arbitrary value (animate-duration-[1.6s], stagger-delay-[90ms]).