Tailwind v4 animation cheatsheet — every motion utility, with examples
Tailwind CSS v4 animations: utility classes, custom keyframes, motion variants. With live examples and copy-pasteable snippets.
Tailwind v4 changed how animations are configured — no more tailwind.config.js, just CSS tokens. If you came from v3 and your animate-* utilities aren't behaving the way you remember, you are not alone. Here is the full motion vocabulary for v4, with live examples and the patterns that hold up in production.
The built-in animations
Tailwind ships five utilities out of the box. They are intentionally limited — the assumption is you'll define your own for anything brand-specific.
| Utility | Effect | Use for |
|---|---|---|
animate-spin | 360° rotation, 1s linear, infinite | Loading spinners only |
animate-ping | Scale + fade, 1s, infinite | Notification dots, ripple states |
animate-pulse | Opacity fade in/out, 2s | Skeleton loaders |
animate-bounce | Vertical bounce, 1s | Scroll indicators |
animate-none | Disables animation | Conditional / motion-reduced contexts |
That's it for built-ins. Everything else is custom.
Defining custom animations in v4
In v4 you define keyframes and animation utilities directly in CSS using @theme:
@import "tailwindcss";
@theme {
--animate-shake: shake 0.4s cubic-bezier(.36,.07,.19,.97) both;
--animate-fade-in: fade-in 0.3s ease-out;
--animate-slide-up: slide-up 0.4s cubic-bezier(.34,1.56,.64,1) both;
@keyframes shake {
10%, 90% { transform: translate3d(-1px, 0, 0); }
20%, 80% { transform: translate3d(2px, 0, 0); }
30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
40%, 60% { transform: translate3d(4px, 0, 0); }
}
@keyframes fade-in { from { opacity: 0; } }
@keyframes slide-up {
from { opacity: 0; transform: translateY(8px); }
}
}Now <div class="animate-shake"> works. The --animate-* token both defines the animation and registers the utility class — one declaration, no separate plugin step.
The motion-reduced variant
motion-safe: and motion-reduce: honor the user's OS preference. Use them on every non-essential animation:
<div class="motion-safe:animate-fade-in motion-reduce:animate-none">
Hello
</div>The rule we follow: any animation that is decorative — fades, slides, attention-grabbers — gets motion-safe:. Any animation that conveys state — a loading spinner, a "you have new mail" pulse — stays on regardless.
Transitions vs. animations (the v4 answer)
Tailwind exposes both. The distinction:
- Transitions (
transition-*) interpolate between two states (hover, focus, class change). Cheap, interruptible, the default for UI. - Animations (
animate-*) run a keyframe sequence regardless of state. Use when you need entry/exit motion or a looping effect.
Most UI work is transitions. Reserve animations for entrance/exit and looping decorations.
<!-- Transition: hover state -->
<button class="transition-transform duration-200 hover:scale-105">
Press me
</button>
<!-- Animation: entry -->
<div class="animate-slide-up">
Hello
</div>The full motion utility list
<!-- Properties -->
transition-all /* all properties */
transition-colors /* color, bg, border */
transition-opacity
transition-shadow
transition-transform
<!-- Duration -->
duration-75 / 100 / 150 / 200 / 300 / 500 / 700 / 1000
<!-- Easing -->
ease-linear
ease-in
ease-out
ease-in-out
<!-- Delay -->
delay-75 / 100 / 150 / 200 / 300 / 500 / 700 / 1000Patterns that work in v4
Three patterns we reach for constantly:
1. The lift-on-hover
<a class="block rounded-xl border p-6 transition-all duration-200
hover:-translate-y-0.5 hover:shadow-lg">Two transforms (-translate-y + shadow), 200ms, all properties. The shadow change is what sells the depth.
2. The press-state button
<button class="rounded-lg bg-red-500 px-4 py-2 text-white
transition-all duration-150
hover:bg-red-600 active:scale-95">active:scale-95 gives a tactile press without a JS handler. The browser handles :active; Tailwind handles the scale.
3. The staggered list
For list entries that fade in with a stagger, use animation-delay via inline style:
{items.map((item, i) => (
<div class="animate-fade-in" style={`animation-delay:${i * 50}ms`}>
{item.text}
</div>
))}50ms is the sweet spot — visible cascade, no awkward delay before the last item.
Rendering Tailwind animations to MP4
Tailwind animations are CSS animations under the hood — they render to MP4 through the HyperFrames pipeline just like any other CSS animation. The one caveat: motion-reduce will follow the rendering browser's preference, so set the rendering environment's prefers-reduced-motion to no-preference for production renders.
Open the playground, drop in a Tailwind component, scrub through the motion timeline.
Cite this postBibTeX · APA · Markdown
@misc{okafor2026tailwind,
author = {Marcus Okafor},
title = {Tailwind v4 animation cheatsheet — every motion utility, with examples},
year = {2026},
url = {https://hyperframes.video/blog/tailwind-animation-cheatsheet},
note = {HyperFrames blog}
}Marcus Okafor. (2026, April 24). Tailwind v4 animation cheatsheet — every motion utility, with examples. HyperFrames. https://hyperframes.video/blog/tailwind-animation-cheatsheet
[Tailwind v4 animation cheatsheet — every motion utility, with examples](https://hyperframes.video/blog/tailwind-animation-cheatsheet) — Marcus Okafor, 2026
Marcus leads design and motion at HyperFrames. Before that he shipped editorial motion for newsrooms and product launches. He thinks every easing curve has a personality.
How to animate your logo (without After Effects)
A logo reveal in pure CSS — spring overshoot, wordmark stagger, and a render straight to MP4. No timeline tool, no plugins.
Scroll-driven video: turning timelines into scroll positions
CSS scroll-driven animations finally went baseline in 2026. A practical tutorial on mapping video timelines to scroll positions, when to use scroll vs video, and the hybrid pattern we use on hyperframes.dev.
Motion graphics in 80 lines
A complete title sequence — bouncy text, parallax backdrop, signal-color accent, cinematic ease — written in 80 lines of plain HTML. No framework. No tooling beyond the browser.
Building with HyperFrames? Come hang out.
We're on GitHub, in Discord, and the playground is one click away. Bring weird ideas — we collect them.