Transitions, transforms and animations
A transition smoothly changes a property from one value to another — for example, a button's color on hover. A transform moves, rotates or scales an element, and an animation plays by itself, without any user action.
Transition
The transition class enables smoothing for colors, opacity, shadows and transforms. duration- sets the length in milliseconds, ease- the type of motion:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<button class="rounded-lg bg-indigo-600 px-4 py-2 text-white transition duration-300 ease-in-out hover:bg-pink-600">
Add to cart
</button>Hover over it — the color flows from blue to pink over 0.3 seconds instead of changing instantly. transition-colors limits the smoothing to colors only, and delay-150 adds a delay.
Transforms
| Class | What it does |
|---|---|
scale-105 | Scales to 105% |
rotate-3 | Rotates by 3 degrees |
translate-x-2 | Moves right by 2 scale steps |
-translate-y-1 | Moves up by 1 step |
Together with a transition, transforms make cards feel "alive" — the card lifts on hover:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="max-w-xs rounded-xl bg-white p-4 shadow transition hover:-translate-y-1 hover:shadow-xl">
<h2 class="font-semibold">Wireless headphones</h2>
<p class="text-gray-600">$79</p>
</div>Ready animations
| Class | What happens | Where it helps |
|---|---|---|
animate-spin | Rotates in a circle | Loading spinner |
animate-ping | An expanding ripple | Notification dot |
animate-pulse | Opacity fades in and out | Loading placeholder |
animate-bounce | Bounces | A "scroll down" arrow |
A card placeholder while the product loads:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="max-w-xs animate-pulse rounded-xl bg-white p-4 shadow">
<div class="h-32 rounded-lg bg-gray-200"></div>
<div class="mt-4 h-4 w-3/4 rounded bg-gray-200"></div>
<div class="mt-2 h-4 w-1/4 rounded bg-gray-200"></div>
</div>Gray rectangles gently fade in and out where the image, name and price will be.
Your own animation
A new animation is added in @theme: an --animate- variable plus a @keyframes rule. In a project this goes into the main CSS file:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<style type="text/tailwindcss">
@theme {
--animate-wiggle: wiggle 0.5s ease-in-out infinite;
@keyframes wiggle {
0%, 100% { transform: rotate(-3deg); }
50% { transform: rotate(3deg); }
}
}
</style>
<span class="inline-block animate-wiggle rounded-full bg-rose-500 px-3 py-1 text-sm text-white">-20%</span>An animate-wiggle class appeared, and the discount badge wiggles.
Common mistake
Overusing motion. Animation distracts some people or even makes them feel sick, so they turn on "Reduce motion" in their system. The motion-reduce: variant respects that setting:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="size-8 animate-spin rounded-full border-4 border-indigo-200 border-t-indigo-600 motion-reduce:animate-none"></div>For users with that setting the spinner does not rotate. Add motion-reduce: to continuous animations.