Animations
Tailwind ships a small built-in animation set (spin, ping, pulse, bounce) plus the building blocks (transition, duration, ease) for state-driven animation. For complex sequences, drop into a CSS keyframe defined in tailwind.config.js or reach for Framer Motion. The built-ins cover most loading states, button feedback, and toast entrances.
Built-ins, transitions, custom keyframes, motion-safe
EXAMPLE
<!-- 1) Built-in spinners and pulses -->
<svg class='animate-spin h-5 w-5 text-white' viewBox='0 0 24 24'>
<circle cx='12' cy='12' r='10' stroke='currentColor' stroke-width='4' fill='none' opacity='.3' />
<path fill='currentColor' d='M4 12a8 8 0 0 1 8-8v2a6 6 0 0 0-6 6H4z' />
</svg>
<span class='animate-ping inline-flex h-3 w-3 rounded-full bg-emerald-400 opacity-75'></span>
<div class='animate-pulse bg-slate-200 h-4 w-32 rounded'></div>
<div class='animate-bounce text-blue-500'>v</div>
<!-- 2) Hover and focus transitions — state-driven, not keyframed -->
<button class='px-3 py-1.5 rounded bg-blue-600 text-white
transition-transform duration-150 ease-out
hover:scale-105 active:scale-95
focus-visible:ring-2 focus-visible:ring-blue-400'>
Save
</button>
<!-- 3) Group hover — child animates on parent hover -->
<a href='#' class='group inline-flex items-center gap-1'>
Continue
<span class='transition-transform duration-200 group-hover:translate-x-1'>→</span>
</a>
<!-- 4) Stagger via delay utilities -->
<div class='space-y-1'>
<p class='opacity-0 animate-fadeUp [animation-delay:0ms]'>One</p>
<p class='opacity-0 animate-fadeUp [animation-delay:80ms]'>Two</p>
<p class='opacity-0 animate-fadeUp [animation-delay:160ms]'>Three</p>
</div>
<!-- 5) Respect 'prefers-reduced-motion' — use motion-safe / motion-reduce variants -->
<div class='motion-safe:animate-bounce motion-reduce:animate-none'>Bouncing only when allowed</div>
<!-- 6) Custom keyframes in tailwind.config.js -->
<!-- tailwind.config.js
module.exports = {
theme: {
extend: {
keyframes: {
fadeUp: { '0%': { opacity: 0, transform: 'translateY(8px)' },
'100%': { opacity: 1, transform: 'translateY(0)' } },
shimmer: { '100%': { transform: 'translateX(100%)' } },
},
animation: {
fadeUp: 'fadeUp .35s ease-out forwards',
shimmer: 'shimmer 1.4s linear infinite',
},
},
},
};
-->
<!-- 7) Skeleton loader with shimmer -->
<div class='relative overflow-hidden bg-slate-200 rounded h-4 w-40'>
<div class='absolute inset-0 -translate-x-full
bg-gradient-to-r from-transparent via-white/50 to-transparent
animate-shimmer'></div>
</div>
<!-- 8) Enter / leave transitions (Headless UI, Vue, Alpine all use Tailwind utilities) -->
<div class='transition duration-200 ease-out
data-[state=open]:opacity-100 data-[state=open]:translate-y-0
data-[state=closed]:opacity-0 data-[state=closed]:translate-y-2
data-[state=closed]:pointer-events-none'>
Toast
</div>
<!-- 9) Performance — animate transform and opacity (GPU-composited).
Avoid animating width / height / margin in hot paths; they trigger layout. -->
Why it matters
Always pair motion with `motion-safe:` (or check `prefers-reduced-motion` in custom CSS). Users who opt out of motion include people with vestibular disorders, and the OS-level setting is the universal contract — respecting it is a 5-character class name and the right thing to do.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…