Skip to content

Tailwind CSS Animations — Transitions, Keyframes, and Motion

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Tailwind CSS Animations. We cover key concepts, practical examples, and best practices to help you master this topic.

Tailwind CSS animation utilities control element motion through transitions (transition-colors, transition-all), built-in keyframe animations (animate-spin, animate-pulse), and custom animation configuration.

What You'll Learn

You will learn how to use transition utilities for smooth state changes, apply built-in animations, configure custom keyframes, control timing and delay, and respect user motion preferences.

Why It Matters

Motion guides attention and improves perceived performance. DodaTech uses Tailwind animations for loading states (animate-pulse), micro-interactions (hover transitions), and page entry effects.

Real-World Use

Durga Antivirus Pro uses animate-pulse for scan progress, transition-transform for button clicks, animate-spin for loading indicators, and custom keyframes for notification slide-ins.

flowchart LR
    A[Pseudo-Classes] --> B[Animations]
    B --> C[Transitions]
    B --> D[Animate Classes]
    B --> E[Keyframes]
    B --> F[Motion Respect]
    style B fill:#38bdf8,stroke:#0284c7,color:#fff
    style C fill:#22c55e,stroke:#16a34a,color:#fff

Transition Properties

<div class="p-8 space-y-8 max-w-lg mx-auto">
  <div class="p-6 bg-white rounded-xl shadow-sm">
    <h3 class="font-bold mb-4">Transition Properties</h3>

    <div class="group p-4 bg-gray-50 rounded-lg hover:bg-blue-50 transition-colors duration-300 cursor-pointer">
      transition-colors: background changes smoothly
    </div>

    <div class="group mt-3 p-4 bg-gray-50 rounded-lg hover:shadow-lg transition-shadow duration-300 cursor-pointer">
      transition-shadow: shadow changes smoothly
    </div>

    <div class="group mt-3 p-4 bg-gray-50 rounded-lg hover:scale-105 transition-transform duration-300 cursor-pointer">
      transition-transform: scale changes smoothly
    </div>

    <div class="group mt-3 p-4 bg-gray-50 rounded-lg hover:translate-x-2 transition-all duration-300 cursor-pointer">
      transition-all: everything changes smoothly
    </div>
  </div>
</div>

Expected output: Four boxes with different transition properties. Each smoothly animates the specified property on hover.

Duration and Timing

<div class="p-8 max-w-lg mx-auto">
  <h3 class="font-bold mb-4">Transition Duration</h3>
  <div class="space-y-3">
    <div class="bg-blue-100 p-4 rounded-lg hover:bg-blue-300 transition-colors duration-75 cursor-pointer">
      duration-75 (75ms) - fastest
    </div>
    <div class="bg-blue-200 p-4 rounded-lg hover:bg-blue-400 transition-colors duration-150 cursor-pointer">
      duration-150 (150ms)
    </div>
    <div class="bg-blue-300 p-4 rounded-lg hover:bg-blue-500 transition-colors duration-300 cursor-pointer">
      duration-300 (300ms)
    </div>
    <div class="bg-blue-400 text-white p-4 rounded-lg hover:bg-blue-600 transition-colors duration-500 cursor-pointer">
      duration-500 (500ms)
    </div>
    <div class="bg-blue-500 text-white p-4 rounded-lg hover:bg-blue-700 transition-colors duration-1000 cursor-pointer">
      duration-1000 (1000ms) - slowest
    </div>
  </div>

  <h3 class="font-bold mt-8 mb-4">Timing Functions</h3>
  <div class="space-y-3">
    <div class="bg-green-100 p-4 rounded-lg hover:translate-x-4 transition ease-linear duration-300 cursor-pointer">
      ease-linear - constant speed
    </div>
    <div class="bg-green-200 p-4 rounded-lg hover:translate-x-4 transition ease-in duration-300 cursor-pointer">
      ease-in - starts slow, ends fast
    </div>
    <div class="bg-green-300 p-4 rounded-lg hover:translate-x-4 transition ease-out duration-300 cursor-pointer">
      ease-out - starts fast, ends slow
    </div>
    <div class="bg-green-400 text-white p-4 rounded-lg hover:translate-x-4 transition ease-in-out duration-300 cursor-pointer">
      ease-in-out - slow both ends
    </div>
  </div>
</div>

Expected output: Boxes slide right on hover with different speeds and timing functions for varied motion feel.

Built-in Animations

<div class="p-8 max-w-lg mx-auto">
  <h3 class="font-bold mb-4">Built-in Animations</h3>
  <div class="grid grid-cols-2 gap-4">
    <div class="flex flex-col items-center p-4 bg-gray-50 rounded-lg">
      <div class="w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
      <p class="text-sm mt-2">animate-spin</p>
    </div>

    <div class="flex flex-col items-center p-4 bg-gray-50 rounded-lg">
      <div class="w-16 h-8 bg-blue-500 rounded animate-pulse"></div>
      <p class="text-sm mt-2">animate-pulse (skeleton)</p>
    </div>

    <div class="flex flex-col items-center p-4 bg-gray-50 rounded-lg">
      <p class="text-lg animate-bounce">Bounce</p>
      <p class="text-sm mt-2">animate-bounce</p>
    </div>

    <div class="flex flex-col items-center p-4 bg-gray-50 rounded-lg">
      <div class="w-16 h-8 bg-blue-500 rounded animate-ping"></div>
      <p class="text-sm mt-2">animate-ping</p>
    </div>
  </div>
</div>

Expected output: Four animated elements: spinning loader, pulsing skeleton, bouncing text, and ping radar effect.

Custom Keyframes

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      keyframes: {
        'slide-in': {
          '0%': { transform: 'translateX(-100%)', opacity: '0' },
          '100%': { transform: 'translateX(0)', opacity: '1' },
        },
        'slide-up': {
          '0%': { transform: 'translateY(20px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
        'fade-in': {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
      },
      animation: {
        'slide-in': 'slide-in 0.3s ease-out',
        'slide-up': 'slide-up 0.4s ease-out',
        'fade-in': 'fade-in 0.5s ease-out',
      },
    },
  },
}
<div class="space-y-4 p-8 max-w-lg mx-auto">
  <div class="animate-slide-in bg-blue-100 p-4 rounded-lg">
    Slides in from left
  </div>
  <div class="animate-slide-up bg-green-100 p-4 rounded-lg">
    Slides up from below
  </div>
  <div class="animate-fade-in bg-purple-100 p-4 rounded-lg">
    Fades in
  </div>
</div>

Expected output: Three elements with custom animations: slide-in, slide-up, and fade-in, each with defined keyframes.

Animation Delay and Iteration

<div class="p-8 max-w-lg mx-auto">
  <h3 class="font-bold mb-4">Animation Delay</h3>
  <div class="space-y-2">
    <div class="h-8 bg-blue-300 rounded animate-slide-in delay-0">delay-0</div>
    <div class="h-8 bg-blue-400 rounded animate-slide-in delay-100">delay-100</div>
    <div class="h-8 bg-blue-500 rounded animate-slide-in delay-200">delay-200</div>
    <div class="h-8 bg-blue-600 rounded animate-slide-in delay-300">delay-300</div>
  </div>

  <h3 class="font-bold mt-8 mb-4">Animation Iteration</h3>
  <div class="flex gap-4">
    <div class="w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin repeat-1"></div>
    <div class="w-8 h-8 border-4 border-green-500 border-t-transparent rounded-full animate-spin repeat-2"></div>
    <div class="w-8 h-8 border-4 border-purple-500 border-t-transparent rounded-full animate-spin repeat-infinite"></div>
  </div>
</div>

Expected output: Elements animate with staggered delays, and spinners with different repetition counts.

Motion Respect (prefers-reduced-motion)

<div class="p-8 max-w-lg mx-auto">
  <!-- Using the motion-safe and motion-reduce variants -->
  <div class="motion-safe:animate-bounce motion-reduce:animate-none bg-blue-100 p-4 rounded-lg">
    Bounces unless user prefers reduced motion
  </div>

  <div class="motion-safe:transition-transform motion-safe:hover:scale-110 motion-reduce:transition-none bg-green-100 p-4 rounded-lg mt-4">
    Scales on hover unless reduced motion is preferred
  </div>
</div>

Expected output: Animations and transitions apply only when the user has not set prefers-reduced-motion. motion-reduce variants provide a static fallback.

Common Mistakes

1. Animating Too Many Properties

transition-all on elements with many properties causes performance issues. Use specific transitions like transition-colors or transition-transform.

2. Not Preventing Layout Shift

CSS animations on elements that move should use transform (GPU-accelerated), not margin or positioning.

3. Forgetting motion-reduce

Without motion-reduce fallbacks, users with vestibular disorders may experience discomfort. Always add motion-reduce:transition-none or motion-reduce:animate-none.

4. Using animate-ping for Persistent Elements

animate-ping is for notification dots and temporary effects. It creates continuous motion that can be distracting.

5. Not Setting Finite Iterations

Infinite animations can be jarring. Use repeat-1, repeat-2, or a finite iteration count for non-loading animations.

Practice Questions

  1. What is the difference between transition and animation? Transitions interpolate between two states (hover to non-hover). Animations run defined keyframes regardless of state changes.

  2. How do you add a custom animation? Define keyframes and animation name in tailwind.config.js under theme.extend.

  3. What utility prevents animation for motion-sensitive users? motion-reduce:animate-none disables animations when prefers-reduced-motion is set.

  4. What is the fastest transition duration? duration-75 (75ms). Available durations: 75, 100, 150, 200, 300, 500, 700, 1000.

  5. How do you delay an animation? delay-{ms} where ms is 75, 100, 150, 200, 300, 500, 700, or 1000.

Challenge

Build an animated notification toast: slides in from the right (custom keyframes), fades out after 3 seconds, uses motion-reduce fallback, has a progress bar that shrinks over time (custom animation), and stacks with gap.

FAQ

Are Tailwind animations GPU-accelerated?

Animations using transform and opacity are GPU-accelerated. Animating width, height, or position uses CPU and may cause layout shifts.

Can I use CSS scroll-driven animations with Tailwind?

Not directly. Use arbitrary values with scroll-driven animation properties.

How do I pause an animation on hover?

Use hover:animate-pause or the running/paused state: hover:[animation-play-state:paused]

Can I use @keyframes with CSS variables?

Yes. Use CSS variables inside keyframes for dynamic animation values.

Do animations work in React/Vue/Svelte?

Yes. Tailwind animations are CSS-based and work with any framework's transition or animation systems.

Mini Project

Build a notification system with: slide-in from top, pulse for new notifications, fade-out on dismiss, motion-reduce support, staggered delays for multiple notifications, and a custom keyframe for progress bars.

What's Next

Now master Transforms for scale, rotate, translate, and skew. Combine transforms with animations for advanced motion effects.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro