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:
| Class | Styles |
|---|---|
animate-delay | animation-delay: 150ms; |
animate-delay-0 | animation-delay: 0s; |
animate-delay-75 | animation-delay: 75ms; |
animate-delay-100 | animation-delay: 100ms; |
animate-delay-150 | animation-delay: 150ms; |
animate-delay-200 | animation-delay: 200ms; |
animate-delay-300 | animation-delay: 300ms; |
animate-delay-500 | animation-delay: 500ms; |
animate-delay-700 | animation-delay: 700ms; |
animate-delay-1000 | animation-delay: 1000ms; |
animate-duration | animation-duration: 150ms; |
animate-duration-0 | animation-duration: 0s; |
animate-duration-75 | animation-duration: 75ms; |
animate-duration-100 | animation-duration: 100ms; |
animate-duration-150 | animation-duration: 150ms; |
animate-duration-200 | animation-duration: 200ms; |
animate-duration-300 | animation-duration: 300ms; |
animate-duration-500 | animation-duration: 500ms; |
animate-duration-700 | animation-duration: 700ms; |
animate-duration-1000 | animation-duration: 1000ms; |
animate-ease | animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); |
animate-ease-in | animation-timing-function: cubic-bezier(0.4, 0, 1, 1); |
animate-ease-in-back | animation-timing-function: cubic-bezier(0.36, 0, 0.66, -0.56); |
animate-ease-in-circ | animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45); |
animate-ease-in-cubic | animation-timing-function: cubic-bezier(0.32, 0, 0.67, 0); |
animate-ease-in-expo | animation-timing-function: cubic-bezier(0.7, 0, 0.84, 0); |
animate-ease-in-out | animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); |
animate-ease-in-out-back | animation-timing-function: cubic-bezier(0.68, -0.6, 0.32, 1.6); |
animate-ease-in-out-circ | animation-timing-function: cubic-bezier(0.85, 0, 0.15, 1); |
animate-ease-in-out-cubic | animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); |
animate-ease-in-out-expo | animation-timing-function: cubic-bezier(0.87, 0, 0.13, 1); |
animate-ease-in-out-quad | animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1); |
animate-ease-in-out-quart | animation-timing-function: cubic-bezier(0.76, 0, 0.24, 1); |
animate-ease-in-out-quint | animation-timing-function: cubic-bezier(0.83, 0, 0.17, 1); |
animate-ease-in-out-sine | animation-timing-function: cubic-bezier(0.37, 0, 0.63, 1); |
animate-ease-in-quad | animation-timing-function: cubic-bezier(0.11, 0, 0.5, 0); |
animate-ease-in-quart | animation-timing-function: cubic-bezier(0.5, 0, 0.75, 0); |
animate-ease-in-quint | animation-timing-function: cubic-bezier(0.64, 0, 0.78, 0); |
animate-ease-in-sine | animation-timing-function: cubic-bezier(0.12, 0, 0.39, 0); |
animate-ease-linear | animation-timing-function: linear; |
animate-ease-out | animation-timing-function: cubic-bezier(0, 0, 0.2, 1); |
animate-ease-out-back | animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); |
animate-ease-out-circ | animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1); |
animate-ease-out-cubic | animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1); |
animate-ease-out-expo | animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); |
animate-ease-out-quad | animation-timing-function: cubic-bezier(0.5, 1, 0.89, 1); |
animate-ease-out-quart | animation-timing-function: cubic-bezier(0.25, 1, 0.5, 1); |
animate-ease-out-quint | animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); |
animate-ease-out-sine | animation-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:
| Class | Styles |
|---|---|
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:
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.
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-1tostagger-10are generated;staggeralone isstagger-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]).