Tailwind Animation and Transition Utilities
Animate hover states, page mounts, and component transitions with Tailwind's transition and animation utilities and a few custom keyframes.
What you'll learn
- ✓How transition utilities map to CSS
- ✓Common animation utilities like spin, ping, pulse, and bounce
- ✓Adding custom keyframes in the config
- ✓Using motion-safe and motion-reduce
- ✓Avoiding janky animations
Prerequisites
- •Comfortable with HTML and JavaScript
What and Why
Subtle motion turns a flat interface into a tactile one. Buttons that smoothly change color on hover feel responsive. Toasts that slide in feel intentional. Tailwind ships utilities for both transitions and keyframe animations, so you can add motion without writing custom CSS for most use cases.
Mental Model
Transitions interpolate between two values when a property changes. Animations play a sequence of keyframes on a schedule. Tailwind exposes both as utilities. transition plus duration-200 plus ease-out covers the common case. animate-spin plays a built-in keyframe.
Transition Animation
state A -> state B keyframe 0% -> 50% -> 100%
triggered by change plays on a timeline
one direction loops or one-shot
Hands-on Example
A button that smoothly changes color and lifts on hover.
<button
class="rounded bg-blue-600 px-4 py-2 text-white transition
duration-200 ease-out hover:-translate-y-0.5 hover:bg-blue-700
active:translate-y-0">
Save
</button>
transition turns on transitions for color, background, transform, opacity, and a few other properties. duration-200 sets 200 milliseconds, and ease-out chooses the timing function. On hover the button slightly rises and darkens. On active state it returns to its resting position for a satisfying click.
A loading indicator with the built-in spin animation.
<svg class="h-5 w-5 animate-spin text-slate-500" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" class="opacity-20" stroke="currentColor" />
<path d="M22 12a10 10 0 0 1-10 10" stroke="currentColor" />
</svg>
A notification that slides in. Add custom keyframes in tailwind.config.js.
module.exports = {
theme: {
extend: {
keyframes: {
slideIn: {
'0%': { transform: 'translateY(-20px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
},
animation: {
'slide-in': 'slideIn 200ms ease-out',
},
},
},
};
Use it on the toast element.
<div role="status" class="animate-slide-in rounded bg-green-600 px-4 py-2 text-white">
Saved successfully
</div>
For users who prefer reduced motion, gate the animation.
<div class="motion-safe:animate-slide-in motion-reduce:opacity-100">
Saved
</div>
The toast still appears for users with reduced motion enabled, just without the slide. This respects the operating system preference and is required by accessibility guidelines.
Common Pitfalls
Animating layout properties like width, height, or top is expensive because each frame triggers reflow. Prefer transform and opacity, which the browser can composite on the GPU. The button example above uses translate-y rather than changing margin-top for that reason.
Forgetting the transition utility means none of your duration, ease, or hover transitions actually animate. The duration and timing utilities only configure a transition that is already turned on. Without transition or transition-colors, the change snaps.
A transition that starts at mount can flash. The element renders with its final state, then animates from nothing. Use a small JavaScript trick to add the class on the next frame, or use a CSS animation that always plays on mount.
Practical Tips
Keep durations short. Most micro interactions feel best between 150 and 250 milliseconds. Anything longer than 400 starts to feel sluggish unless it is a meaningful transition like a modal opening.
Use ease-out for entrances and ease-in for exits. Entrances should slow into place; exits should accelerate away. Tailwind ships both as utilities.
Combine transition-transform, transition-opacity, and transition-colors instead of the catch-all transition when you want to limit which properties animate. This is faster and avoids unintended interpolation on properties you do not control.
Test on a low-powered device. A complex hover animation that looks smooth on a developer laptop can chug on a budget Android. The browser performance panel and the FPS meter show exactly where the time goes.
Wrap-up
Tailwind covers everyday motion with a small set of composable utilities. Reach for transitions on hover, focus, and state changes; reach for animations on mount, loading, and attention-grabbing moments. Stick to transform and opacity, respect reduced motion, and your interface will feel alive without becoming exhausting.
Related articles
- Tailwind Tailwind Arbitrary Values and the JIT Engine
How Tailwind's JIT engine generates classes on demand, when arbitrary values are the right tool, and how to keep your design system tidy.
- Tailwind Tailwind Custom Plugins Tutorial
Write your own Tailwind plugins to add utilities, components, and variants that match your design system without reaching for arbitrary values everywhere.
- Tailwind Customizing Tailwind: Theme and Design Tokens
Extend Tailwind's theme with custom colors, spacing, and design tokens that scale across a real product without fighting the framework.
- Tailwind Tailwind Dark Mode Strategies: Class, Media, and CSS Variables
Compare the class-based, media-based, and variable-driven approaches to dark mode in Tailwind, with code and the trade-offs of each.