Skip to main content

Animations

In this chapter, you learn how to implement animations with Tailwind CSS.

Transitions

Basics

<!-- Enable transitions -->
<button class="transition bg-blue-500 hover:bg-blue-600">
Transitions automatically
</button>

Transition properties

ClassTarget property
transition-noneNone
transition-allAll
transitionCommon properties
transition-colorsColor-related
transition-opacityOpacity
transition-shadowShadow
transition-transformTransform
<button class="transition-colors bg-blue-500 hover:bg-blue-600">
Transition colors only
</button>

<div class="transition-transform hover:scale-105">
Transition transform only
</div>

Duration

<div class="transition duration-75">75ms</div>
<div class="transition duration-100">100ms</div>
<div class="transition duration-150">150ms (default)</div>
<div class="transition duration-200">200ms</div>
<div class="transition duration-300">300ms</div>
<div class="transition duration-500">500ms</div>
<div class="transition duration-700">700ms</div>
<div class="transition duration-1000">1000ms</div>

Easing

<div class="transition ease-linear">Linear</div>
<div class="transition ease-in">Slow at the start</div>
<div class="transition ease-out">Slow at the end</div>
<div class="transition ease-in-out">Slow at both ends</div>

Delay

<div class="transition delay-75">75ms delay</div>
<div class="transition delay-100">100ms delay</div>
<div class="transition delay-150">150ms delay</div>
<div class="transition delay-200">200ms delay</div>
<div class="transition delay-300">300ms delay</div>
<div class="transition delay-500">500ms delay</div>

Transform

Scale (enlarge / shrink)

<div class="scale-0">0%</div>
<div class="scale-50">50%</div>
<div class="scale-75">75%</div>
<div class="scale-90">90%</div>
<div class="scale-100">100% (default)</div>
<div class="scale-105">105%</div>
<div class="scale-110">110%</div>
<div class="scale-125">125%</div>
<div class="scale-150">150%</div>

<!-- X axis / Y axis individually -->
<div class="scale-x-50">Horizontal 50%</div>
<div class="scale-y-150">Vertical 150%</div>

Rotate

<div class="rotate-0">0 degrees</div>
<div class="rotate-45">45 degrees</div>
<div class="rotate-90">90 degrees</div>
<div class="rotate-180">180 degrees</div>
<div class="-rotate-45">-45 degrees</div>

Translate

<div class="translate-x-4">16px to the right</div>
<div class="translate-y-4">16px down</div>
<div class="-translate-x-4">16px to the left</div>
<div class="-translate-y-4">16px up</div>
<div class="translate-x-1/2">50% to the right</div>
<div class="-translate-x-1/2 -translate-y-1/2">50% to the upper left on each axis</div>

Skew

<div class="skew-x-6">Skew 6 degrees on the X axis</div>
<div class="skew-y-6">Skew 6 degrees on the Y axis</div>
<div class="-skew-x-6">Skew -6 degrees on the X axis</div>

Transform origin

<div class="origin-center">Center (default)</div>
<div class="origin-top">Top</div>
<div class="origin-top-right">Top right</div>
<div class="origin-right">Right</div>
<div class="origin-bottom-right">Bottom right</div>
<div class="origin-bottom">Bottom</div>
<div class="origin-bottom-left">Bottom left</div>
<div class="origin-left">Left</div>
<div class="origin-top-left">Top left</div>

3D transforms (v4)

3D transforms use the GPU, but watch out for memory consumption

3D transforms use the transform property, so GPU acceleration kicks in. However, heavy use of perspective or transform-3d may increase memory consumption. In complex 3D scenes, apply them only to the elements that need them.

In v4, 3D transforms are supported.

Perspective

<!-- Named values -->
<div class="perspective-normal">Standard perspective (500px)</div>
<div class="perspective-midrange">Mid-range perspective (800px)</div>

<!-- Specifying an arbitrary value -->
<div class="perspective-[500px]">500px perspective</div>
<div class="perspective-[1000px]">1000px perspective</div>
When to use named perspective values versus arbitrary values

The v4 perspective utilities use named values such as perspective-dramatic (100px) and perspective-near (300px). Others include perspective-normal (500px), perspective-midrange (800px), and perspective-distant (1200px). Specify an arbitrary px value with bracket syntax (perspective-[500px]).

3D rotation

<div class="rotate-x-45">Rotate 45 degrees on the X axis</div>
<div class="rotate-y-45">Rotate 45 degrees on the Y axis</div>
<div class="rotate-z-45">Rotate 45 degrees on the Z axis</div>

3D translation

<div class="translate-z-10">Translate on the Z axis</div>

Preserving 3D rendering

<div class="transform-3d">Preserve 3D space</div>
<div class="transform-flat">Make it flat</div>

Backface visibility

<div class="backface-visible">Show the backface</div>
<div class="backface-hidden">Hide the backface</div>

Built-in animations

spin (rotation)

<svg class="animate-spin h-5 w-5">...</svg>

ping (ripple)

<span class="relative flex h-3 w-3">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-3 w-3 bg-blue-500"></span>
</span>

pulse (pulsing)

<div class="animate-pulse bg-gray-200 h-4 rounded-sm"></div>

bounce

<svg class="animate-bounce h-6 w-6"></svg>

Controlling animations

Tailwind v4's core built-in animations are the five animate-spin / animate-ping / animate-pulse / animate-bounce / animate-none. Utilities to change the iteration count, direction, or play state are not provided in the core, so specify them individually with arbitrary-property syntax (for complex animations, define --animate-* with @theme as in Customization).

<!-- Iteration count (animate-spin is infinite, so override with an arbitrary property) -->
<div class="animate-spin [animation-iteration-count:1]">1 time</div>
<div class="animate-spin [animation-iteration-count:2]">2 times</div>

<!-- Direction -->
<div class="animate-spin [animation-direction:reverse]">Reverse</div>
<div class="animate-spin [animation-direction:alternate]">Alternate</div>

<!-- Play state (pause on hover) -->
<div class="animate-spin hover:[animation-play-state:paused]">Pause on hover</div>

Practical examples

Hover animations

<!-- Card hover -->
<div class="transition-all duration-300 hover:scale-105 hover:shadow-xl">
<div class="bg-white rounded-lg shadow-sm p-6">
Card content
</div>
</div>

<!-- Button hover -->
<button class="relative overflow-hidden bg-blue-500 text-white px-6 py-3 rounded-lg group">
<span class="relative z-10">Hover me</span>
<span class="absolute inset-0 bg-blue-600 transform scale-x-0 group-hover:scale-x-100 transition-transform origin-left"></span>
</button>

<!-- Image hover -->
<div class="overflow-hidden rounded-lg">
<img
src="..."
class="transition-transform duration-500 hover:scale-110"
/>
</div>

Fade-in

<!-- Implemented with a CSS animation -->
<style>
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>

<div class="animate-[fade-in_0.5s_ease-out]">
Fade-in content
</div>

Loading spinner

<div class="flex items-center justify-center">
<div class="animate-spin rounded-full h-12 w-12 border-4 border-blue-500 border-t-transparent"></div>
</div>

<!-- Dot loading -->
<div class="flex gap-1">
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce [animation-delay:-0.3s]"></div>
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce [animation-delay:-0.15s]"></div>
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce"></div>
</div>

Skeleton loading

<div class="animate-pulse space-y-4">
<div class="h-4 bg-gray-200 rounded-sm w-3/4"></div>
<div class="h-4 bg-gray-200 rounded-sm"></div>
<div class="h-4 bg-gray-200 rounded-sm w-5/6"></div>
<div class="flex gap-4">
<div class="h-12 w-12 bg-gray-200 rounded-full"></div>
<div class="flex-1 space-y-2 py-1">
<div class="h-4 bg-gray-200 rounded-sm w-1/2"></div>
<div class="h-4 bg-gray-200 rounded-sm w-1/4"></div>
</div>
</div>
</div>

Accordion

<details class="group border border-gray-300 rounded-lg">
<summary class="flex justify-between items-center p-4 cursor-pointer">
<span>Accordion title</span>
<svg class="w-5 h-5 transition-transform duration-200 group-open:rotate-180">

</svg>
</summary>
<div class="overflow-hidden transition-all duration-300 max-h-0 group-open:max-h-screen">
<div class="p-4 pt-0">
Accordion content...
</div>
</div>
</details>

The open: variant applies only to elements that can have an open attribute, such as <details> and <dialog>. Use a <dialog> element and toggle the display based on the presence of the open attribute.

<!-- Overlay (the dialog itself doubles as the overlay) -->
<dialog class="group fixed inset-0 bg-black/50 transition-opacity duration-300
opacity-0 open:opacity-100">

<!-- Modal -->
<div class="fixed inset-0 flex items-center justify-center p-4">
<div class="bg-white rounded-xl shadow-xl max-w-lg w-full
transform transition-all duration-300
scale-95 opacity-0 group-open:scale-100 group-open:opacity-100">
Modal content
</div>
</div>
</dialog>

Underline animation

<a href="#" class="relative inline-block group">
Link text
<span class="absolute bottom-0 left-0 w-full h-0.5 bg-blue-500
transform scale-x-0 group-hover:scale-x-100
transition-transform duration-300 origin-left"></span>
</a>

Card flip

<div class="perspective-[1000px] w-64 h-40">
<div class="relative w-full h-full transition-transform duration-500
transform-3d hover:rotate-y-180">
<!-- Front -->
<div class="absolute inset-0 backface-hidden bg-blue-500 text-white
rounded-lg flex items-center justify-center">
Front
</div>
<!-- Back -->
<div class="absolute inset-0 backface-hidden bg-purple-500 text-white
rounded-lg flex items-center justify-center rotate-y-180">
Back
</div>
</div>
</div>

Animation best practices

1. Be mindful of performance

<!-- Good: use transform / opacity (GPU acceleration) -->
<div class="transition-transform hover:translate-x-2">...</div>

<!-- Avoid: use left / top (triggers reflow) -->
<div class="transition-all hover:left-2">...</div>

2. Consider accessibility

prefers-reduced-motion is a media query that corresponds to the OS "reduce motion" setting. Use it to accommodate users with vestibular disorders and users who prefer less motion-heavy UI.

<!-- motion-safe: animate only when motion is allowed -->
<div class="motion-safe:animate-bounce motion-reduce:animate-none">
...
</div>

<!-- motion-reduce: an alternative for reduced motion -->
<div class="transition-transform motion-safe:hover:scale-105 motion-reduce:hover:opacity-80">
Indicate the change with opacity instead of scale
</div>
Make motion-safe the default

On pages that use a lot of animation, we recommend making motion-safe: your default. This way, users with the reduce-motion setting get the no-animation state by default.

3. Appropriate durations

<!-- Micro-interactions: 100-200ms -->
<button class="transition-colors duration-150">...</button>

<!-- Page transitions / modals: 200-300ms -->
<div class="transition-all duration-300">...</div>

<!-- Emphasis: 300-500ms -->
<div class="transition-transform duration-500">...</div>

Summary

  • Enable transitions with transition
  • Customize with duration-* / ease-* / delay-*
  • Transform with scale-* / rotate-* / translate-*
  • v4 supports 3D transforms
  • Built-in animations such as animate-spin / animate-pulse
  • Support accessibility with motion-safe: / motion-reduce: