Jesse A. Green / notebook

Animate.css User Guide

Generated May 2026 from animate-css/animate.css at 3f8ab23

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Just-add-water CSS animation. A cross-browser library of 97 ready-to-use CSS animations — drop in a stylesheet, add two class names, and any element springs to life.

Animate.css is pure CSS. There is nothing to initialize, no runtime dependency, no framework to learn. If you can write HTML, you can use it today.


1. Quick Start

Add the minified stylesheet from a CDN to your page's <head>:

<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>

Give any element the class animate__animated plus any animation class (all animation classes use the animate__ prefix):

<h1 class="animate__animated animate__bounce">An animated element</h1>

Reload the page. The <h1> bounces. That's the entire API.

Expected result: the heading plays a one-second "bounce" on page load
and stays in place afterward.

Tip

You always need two classes: animate__animated (the enabler that sets duration, fill-mode, and the base transform hooks) plus exactly one animation class (for example animate__fadeIn). Neither class does anything useful on its own.

What to try next:

  • Browse the full Animation Catalog in section 6
  • Customize speed and delay with Utility Classes in section 5
  • See JavaScript Integration in section 8 for event-driven animations

2. Installation

System requirements

Requirement Value
Browser Any evergreen browser (> 3% marketshare, last 2 versions)
JavaScript Not required
Build tools Not required (optional for npm/bundler workflows)

Installation methods

CDN (zero-install)

<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>

Drop this into <head>. No build step, no bundler, no package manager.

npm

npm install animate.css --save
added 1 package, and audited N packages in Xs

Yarn

yarn add animate.css

Yarn only helps if you are already using a bundler (Webpack, Vite, Parcel, Rollup, esbuild). If you are not, use the CDN method.

Import in JS

import 'animate.css';

This pulls in animate.css (the main field of package.json) — the prefixed, unminified build. If your bundler minifies CSS for you, this is the file you want.

Import the minified build

import 'animate.css/animate.min.css';

Use this if your pipeline does not minify CSS automatically. All three distributed files (animate.css, animate.min.css, animate.compat.css) are shipped in the npm package.

Important

The npm package ships three CSS files at the package root: animate.css (prefixed, unminified), animate.min.css (prefixed, minified, the production build), and animate.compat.css (minified, no prefix — the v3 drop-in replacement). Pick exactly one.

Which file do I import?

File Prefix Minified Use when
animate.css animate__ no Development, or when your pipeline minifies CSS
animate.min.css animate__ yes Production — the CDN default
animate.compat.css none yes Migrating from v3.x where your HTML already uses unprefixed classes (bounce, fadeIn, ...)

Post-install verification

After including the stylesheet, verify it works:

<p class="animate__animated animate__fadeIn">If you see this fade in, it works.</p>
Expected result: the paragraph fades in over 1 second on page load.

Warning

The prefers-reduced-motion media query is respected in all three builds. If your OS has "reduce motion" enabled, animations complete in 1ms — effectively instant. This is by design, not a bug. See section 10 for details.


3. Configuration

Animate.css uses three CSS custom properties for runtime configuration. No config files, no environment variables, no build-time settings for consumers.

3.1 The three custom properties

Property Default What it controls
--animate-duration 1s Base duration for .animate__animated and all speed utilities
--animate-delay 1s Base delay for every animate__delay-* class
--animate-repeat 1 Base iteration count for every animate__repeat-* class (not animate__infinite)

Change any of them at any scope (:root, a component class, an element id, inline style) and every child picks up the new value.

/* Global slow-motion */
:root { --animate-duration: 2s; }

/* Marketing section: snappy */
.marketing-hero { --animate-duration: 400ms; }

From JavaScript:

// Half-speed everywhere
document.documentElement.style.setProperty('--animate-duration', '2s');

// Double-speed for this element only
myEl.style.setProperty('--animate-duration', '0.5s');

Tip

Scope overrides to specific components rather than :root when possible. A global --animate-duration: 200ms makes every animation on the page snappy, which may not be desirable for exit animations that need time to read.

3.2 The animate__ prefix

Since v4.0.0, every class name is namespaced with animate__. A class that was called bounce in v3 is now animate__bounce. This eliminates collisions with Bootstrap, Tailwind, Bulma, and any project that used generic names like .fadeIn.

<!-- v3 and earlier (still works via animate.compat.css) -->
<div class="animated bounce">...</div>

<!-- v4+ default -->
<div class="animate__animated animate__bounce">...</div>

3.3 The two-class pattern

Every animation uses the same two-class recipe:

<div class="animate__animated animate__<NAME>">...</div>
  • animate__animated — wires up the shared machinery: animation-duration: var(--animate-duration) and animation-fill-mode: both. Without it, nothing animates.
  • animate__<NAME> — picks which keyframe runs. For example, animate__fadeInLeft, animate__bounceOutUp, or animate__rubberBand.

Note

Because animation-fill-mode: both is the default, an element animated with animate__fadeOut stays invisible after the animation finishes. It does not re-appear. This is by design — see section 9 for patterns that work with this behavior.

For the full configuration reference (build-time prefix customization, per-animation duration overrides), see the Admin Guide.


4. Core Usage

4.1 Animate on page load

Just add the classes in your HTML. The browser plays the animation as soon as the element renders.

<header class="animate__animated animate__fadeInDown">
  Welcome to the show.
</header>

4.2 Trigger an animation on a user action

Flip classes on with JavaScript.

<button id="btn">Click me</button>
<div id="target">Surprise</div>

<script>
  const btn = document.getElementById('btn');
  const target = document.getElementById('target');
  btn.addEventListener('click', () => {
    target.classList.add('animate__animated', 'animate__tada');
  });
</script>

4.3 Play an animation and clean up when it ends

The animationend event fires once per run. Remove the classes so the element can animate again next time.

const el = document.querySelector('.my-element');
el.classList.add('animate__animated', 'animate__bounce');
el.addEventListener('animationend', () => {
  el.classList.remove('animate__animated', 'animate__bounce');
}, { once: true });

Note

The { once: true } listener option matters — without it, if you re-add the classes later, the same handler fires a second time.

4.4 A reusable "play once" helper

A utility function that wraps the add-animate-remove cycle in a Promise:

const animateCSS = (element, animation, prefix = 'animate__') =>
  new Promise((resolve) => {
    const animationName = `${prefix}${animation}`;
    const node = document.querySelector(element);

    node.classList.add(`${prefix}animated`, animationName);

    function handleAnimationEnd(event) {
      event.stopPropagation();
      node.classList.remove(`${prefix}animated`, animationName);
      resolve('Animation ended');
    }

    node.addEventListener('animationend', handleAnimationEnd, { once: true });
  });

// Usage
animateCSS('.my-element', 'bounce');

animateCSS('.my-element', 'bounce').then(() => {
  // something else after the animation finishes
});

4.5 Animate an element out before removing it

Because exit animations end with opacity: 0 (or equivalent), you can chain a real DOM removal on animationend:

function dismiss(el) {
  el.classList.add('animate__animated', 'animate__fadeOutUp');
  el.addEventListener('animationend', () => el.remove(), { once: true });
}

4.6 Loop an animation

<span class="animate__animated animate__pulse animate__infinite">NEW</span>

Warning

Infinite animations pull the eye constantly and rapidly become annoying. Use them only for genuinely transient UI (a live-indicator dot on a dashboard, a spinner during loading) and remove them the moment the condition ends.

4.7 Use @keyframes directly in your own CSS

You do not have to use the animate.css classes at all. The @keyframes are globally defined and can be referenced from your own rules:

.my-element {
  animation-name: bounce;       /* referenced from animate.css */
  animation-duration: 2s;       /* YOU must set a duration */
  animation-fill-mode: both;    /* typical */
}

Caution

Some animations depend on properties set by the wrapper class (.animate__bounce sets transform-origin: center bottom, .animate__flipInX sets backface-visibility: visible !important, .animate__hinge sets a 2x duration). If you reference only the @keyframes and skip the class, those properties are missing and the animation will look subtly or dramatically wrong. When in doubt, use the class.


5. Utility Classes

Utility classes live alongside the animation classes on the same element. All of them key off the same three CSS custom properties so you can override behavior globally or per-element.

5.1 Delay classes

Put off the animation's start by a multiple of --animate-delay (default 1s).

<div class="animate__animated animate__bounce animate__delay-2s">Bounces after 2 seconds</div>
Class Default delay Formula
animate__delay-1s 1s var(--animate-delay)
animate__delay-2s 2s calc(var(--animate-delay) * 2)
animate__delay-3s 3s calc(var(--animate-delay) * 3)
animate__delay-4s 4s calc(var(--animate-delay) * 4)
animate__delay-5s 5s calc(var(--animate-delay) * 5)

Override the delay base globally or per element:

/* All delay classes wait 2x longer */
:root { --animate-delay: 2s; }

/* Only this element starts after 0.5s */
.hero { --animate-delay: 0.5s; }

5.2 Speed classes

Bend duration without changing the animation's rhythm.

<div class="animate__animated animate__bounce animate__faster">Fast bounce</div>
Class Default duration Formula
animate__slower 3s calc(var(--animate-duration) * 3)
animate__slow 2s calc(var(--animate-duration) * 2)
(no class) 1s var(--animate-duration)
animate__fast 800ms calc(var(--animate-duration) * 0.8)
animate__faster 500ms calc(var(--animate-duration) / 2)

Note

A few animations override duration internally: hinge is 2s (slow fall feels natural), bounceIn and bounceOut are 0.75s, flipOutX and flipOutY are 0.75s, and heartBeat is 1.3s. Speed utility classes still apply on top via calc(), so the ratios are preserved when you change the global --animate-duration.

5.3 Repeat classes

<div class="animate__animated animate__bounce animate__repeat-2">Bounces twice</div>
Class Default count Formula
animate__repeat-1 1 var(--animate-repeat)
animate__repeat-2 2 calc(var(--animate-repeat) * 2)
animate__repeat-3 3 calc(var(--animate-repeat) * 3)
animate__infinite infinite (fixed — ignores --animate-repeat)

Important

animate__infinite is not derived from --animate-repeat. Setting --animate-repeat: 10 does nothing to it. Use it only when you truly want to loop forever.


6. Animation Catalog

The library ships 97 animations in 16 categories. Every class name below is the unprefixed animation name — remember to prepend animate__ in your HTML (for example animate__fadeInLeft).

Tip

All names use camelCase and encode direction suffixes: -Down, -Up, -Left, -Right, -TopLeft, -TopRight, -BottomLeft, -BottomRight, -Big (longer travel distance), X / Y (axis). Once you know fadeInLeft exists, you can guess fadeInRight, fadeInUp, and fadeInDownBig.

6.1 Attention seekers (12)

Small in-place animations to draw the eye without moving or hiding the element. Perfect for a "look here" nudge on a button or badge.

Class Feel
bounce Quick vertical hop with a squash on landing
flash Blinks opacity 1 -> 0 -> 1 -> 0 -> 1
pulse Soft scale from 1.0 to 1.05 to 1.0
rubberBand Stretches horizontally then vertically — cartoon stretch
shakeX Side-to-side (horizontal) shake
shakeY Up-and-down (vertical) shake
headShake Short "no" head-shake — shorter travel than shakeX
swing Pendulum from the top of the element
tada Scale-down, wiggle, scale-up (celebration)
wobble Translated sway with slight rotation
jello Skew-based jiggle
heartBeat Two quick scale pulses (duration internally 1.3x)

Note

The v3 shake (a unified horizontal shake class) was split into shakeX / shakeY in v4 and the original shake is not included in the built animate.min.css. If you need it by name, use animate.compat.css (which ships the original v3 class names).

6.2 Back entrances (4)

Element arrives from off-screen, scaled down, and settles in place.

Class From
backInDown Top
backInUp Bottom
backInLeft Left
backInRight Right

6.3 Back exits (4)

Element pulls back and leaves off-screen.

Class To
backOutDown Bottom
backOutUp Top
backOutLeft Left
backOutRight Right

6.4 Bouncing entrances (5)

Spring-in with a settle-overshoot. Internal duration is 0.75s (shorter than the 1s baseline) so the bounce feels snappy.

Class From
bounceIn Scale in (center)
bounceInDown Top
bounceInUp Bottom
bounceInLeft Left
bounceInRight Right

6.5 Bouncing exits (5)

Spring-out, internal 0.75s duration.

Class To
bounceOut Scale out (center)
bounceOutDown Bottom
bounceOutUp Top
bounceOutLeft Left
bounceOutRight Right

6.6 Fading entrances (13)

The most commonly used category — cheap, unobtrusive, and reliable on any device.

Class From
fadeIn In-place (opacity only)
fadeInDown Top (short travel)
fadeInUp Bottom (short travel)
fadeInLeft Left (short travel)
fadeInRight Right (short travel)
fadeInDownBig Top (full viewport)
fadeInUpBig Bottom (full viewport)
fadeInLeftBig Left (full viewport)
fadeInRightBig Right (full viewport)
fadeInTopLeft Diagonal from top-left
fadeInTopRight Diagonal from top-right
fadeInBottomLeft Diagonal from bottom-left
fadeInBottomRight Diagonal from bottom-right

6.7 Fading exits (13)

Mirror of fading entrances — every fadeIn* has a matching fadeOut*.

Class To
fadeOut In-place (opacity only)
fadeOutDown Bottom (short travel)
fadeOutUp Top (short travel)
fadeOutLeft Left (short travel)
fadeOutRight Right (short travel)
fadeOutDownBig Bottom (full viewport)
fadeOutUpBig Top (full viewport)
fadeOutLeftBig Left (full viewport)
fadeOutRightBig Right (full viewport)
fadeOutTopLeft Diagonal top-left
fadeOutTopRight Diagonal top-right
fadeOutBottomLeft Diagonal bottom-left
fadeOutBottomRight Diagonal bottom-right

6.8 Flippers (5)

3D flip effects. Exits use internal 0.75s duration. All flipper animations set backface-visibility: visible !important.

Class Axis / style
flip Full horizontal barrel roll using perspective(400px) + translate3d(0, 0, 150px) mid-flight
flipInX Fold in around horizontal axis
flipInY Fold in around vertical axis
flipOutX Fold out around horizontal axis (0.75s)
flipOutY Fold out around vertical axis (0.75s)

Warning

The flip animation uses perspective(400px) plus a translate3d(0, 0, 150px) mid-flight. If the element's parent has overflow: hidden, the mid-flip frame may clip. Test on your actual layout.

6.9 Lightspeed (4)

Skew-and-slide effect, feels cinematic.

Class Direction
lightSpeedInRight In, from right
lightSpeedInLeft In, from left
lightSpeedOutRight Out, to right
lightSpeedOutLeft Out, to left

6.10 Rotating entrances (5)

Rotational entrance, pivoting around one corner.

Class Pivot
rotateIn Center
rotateInDownLeft Down, from left
rotateInDownRight Down, from right
rotateInUpLeft Up, from left
rotateInUpRight Up, from right

6.11 Rotating exits (5)

Mirror of rotating entrances.

Class Pivot
rotateOut Center
rotateOutDownLeft Down, to left
rotateOutDownRight Down, to right
rotateOutUpLeft Up, to left
rotateOutUpRight Up, to right

6.12 Sliding entrances (4)

Linear slide from the named side.

Class From
slideInDown Top
slideInUp Bottom
slideInLeft Left
slideInRight Right

6.13 Sliding exits (4)

Linear slide to the named side.

Class To
slideOutDown Bottom
slideOutUp Top
slideOutLeft Left
slideOutRight Right

6.14 Zooming entrances (5)

Scale-up entrance, optionally paired with a travel direction.

Class From
zoomIn Center
zoomInDown Top
zoomInUp Bottom
zoomInLeft Left
zoomInRight Right

6.15 Zooming exits (5)

Scale-down exit.

Class To
zoomOut Center
zoomOutDown Bottom
zoomOutUp Top
zoomOutLeft Left
zoomOutRight Right

6.16 Specials (4)

Standalone character effects that do not fit the entrance/exit taxonomy.

Class Feel
hinge A hinged-in-the-corner fall, like a sign coming off the wall. Internal duration 2s — a hinge at 1s feels wrong.
jackInTheBox Scales up and wiggle-rotates from the bottom center.
rollIn Rolls in from the left, rotating -120deg.
rollOut Rolls out to the right, rotating 120deg.

Note

The hinge animation ends with the element translated +700px vertically and opacity 0. If the parent has overflow: hidden, the fall will clip; otherwise the element covers part of your layout for the duration. Plan the surrounding container accordingly.


7. Common Tasks

7.1 Stagger a list of items

There is no built-in stagger utility, but the animate__delay-* classes get you most of the way. Assign increasing delays:

<ul>
  <li class="animate__animated animate__fadeInUp">First</li>
  <li class="animate__animated animate__fadeInUp animate__delay-1s">Second</li>
  <li class="animate__animated animate__fadeInUp animate__delay-2s">Third</li>
</ul>

For a tighter rhythm, override --animate-delay:

li:nth-child(1) { --animate-delay: 100ms; }
li:nth-child(2) { --animate-delay: 200ms; }
li:nth-child(3) { --animate-delay: 300ms; }
<li class="animate__animated animate__fadeInUp animate__delay-1s">...</li>

7.2 Animate only when an element scrolls into view

Animate.css ships no scroll logic. Pair it with an IntersectionObserver:

const io = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add('animate__animated', 'animate__fadeInUp');
      io.unobserve(entry.target);
    }
  });
});

document.querySelectorAll('.reveal').forEach((el) => io.observe(el));
<section class="reveal">Appears when scrolled to.</section>

7.3 Replay an animation on demand

You cannot replay by re-adding the same class — the browser considers the animation unchanged and does nothing. Two workable patterns:

Pattern A — remove then re-add next frame:

el.classList.remove('animate__animated', 'animate__bounce');
// Force reflow so the browser sees "animation removed, now added again"
void el.offsetWidth;
el.classList.add('animate__animated', 'animate__bounce');

Pattern B — use the animateCSS helper (section 4.4):

await animateCSS('#thing', 'bounce');
await animateCSS('#thing', 'bounce'); // plays cleanly the second time

7.4 Page-transition pattern (SPA)

async function goTo(url) {
  await animateCSS('main', 'fadeOutLeft');
  const html = await fetch(url).then((r) => r.text());
  document.querySelector('main').innerHTML = extractMain(html);
  await animateCSS('main', 'fadeInRight');
}

7.5 Interval between repeats

Pure CSS cannot insert a gap between animation iterations. Drop animate__infinite / animate__repeat-* and re-trigger on a timer instead:

function pulseForever(el) {
  setInterval(() => {
    el.classList.remove('animate__pulse');
    void el.offsetWidth;
    el.classList.add('animate__animated', 'animate__pulse');
  }, 2000);
}

7.6 Framework integration snippets

React

import 'animate.css';

function Alert({ message }) {
  return (
    <div className="animate__animated animate__fadeInDown">
      {message}
    </div>
  );
}

Vue

<template>
  <div class="animate__animated animate__fadeInDown">{{ message }}</div>
</template>

<script setup>
import 'animate.css';
defineProps({ message: String });
</script>

Svelte

<script>
  import 'animate.css';
  export let message = '';
</script>

<div class="animate__animated animate__fadeInDown">{message}</div>

Angular

In angular.json add the CSS to the styles array:

"styles": [
  "src/styles.css",
  "node_modules/animate.css/animate.min.css"
]

Then use classes in any template:

<div class="animate__animated animate__fadeInDown">Hello</div>

Tip

For any framework, the pattern is the same: import the CSS once globally, then apply classes. No framework-specific adapter is needed.

7.7 Migrate from v3 to v4

v3.x and earlier used unprefixed class names (.animated, .bounce, .fadeIn). v4 added an animate__ prefix to avoid collisions — this is the only breaking change.

Option A — use the compat build (fastest):

Replace your stylesheet import with the compat file. Your existing HTML keeps working unchanged.

<!-- v4 with v3 class names -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.compat.css" />

Option B — adopt the animate__ prefix:

Do a find-and-replace across your codebase: animated becomes animate__animated, bounce becomes animate__bounce, and so on.

Caution

The compat build may be removed in a future major version. Treat it as a migration aid, not a long-term solution. Also note that the v3 shake class was split into shakeX / shakeY in v4 — if you used shake, switch to shakeX or stay on the compat build.


8. JavaScript Integration

Animate.css is pure CSS — the library itself exposes no JavaScript API. Integration is done through the standard Element / Animation DOM APIs.

8.1 Listening for the end of an animation

el.addEventListener('animationend', (event) => {
  console.log(event.animationName); // e.g. "bounceOutLeft"
}, { once: true });
  • Use { once: true } to auto-remove the listener.
  • Call event.stopPropagation() if a parent also has animations and you do not want its animationend to bubble up.

8.2 Animation events

Event When
animationstart Fires at the start of each animation
animationiteration Fires between iterations when animation-iteration-count > 1
animationend Fires when the animation completes (or is cancelled by removing the class)
animationcancel Fires when the animation is interrupted before completing

8.3 Reading and writing the custom properties from JS

// Read
const duration = getComputedStyle(el).getPropertyValue('--animate-duration');

// Write (this element only)
el.style.setProperty('--animate-duration', '0.6s');

// Write (global)
document.documentElement.style.setProperty('--animate-duration', '2s');

Note

Custom property overrides set via JavaScript follow the CSS cascade — an inline style.setProperty() has the highest specificity and overrides any stylesheet-level custom property value.


9. Best Practices

9.1 Animations should mean something

Use entrance / exit animations to communicate a state change (new element appeared, element is leaving). Use attention-seekers (bounce, pulse, flash) to point at a specific thing the user needs to notice. Avoid animating purely for decoration.

9.2 Animate small, focused elements

Animating huge hero sections, full-page takeovers, or entire layouts is rarely performant and usually hurts UX. Animate the thing that changed, not the whole screen.

9.3 Do not animate <html> or <body>

There have been real browser bugs tied to animating root elements, and the user experience of a bouncing page is poor. If you want a page-level effect, wrap your content in a <main> and animate that.

9.4 Limit infinite animations

animate__infinite attracts attention forever, which quickly becomes attention-fatigue. Use it only for UI states where "something is ongoing" is the actual message.

9.5 Mind the final state

Every animation has animation-fill-mode: both — the element holds the end state after the animation finishes. For exit animations, the element remains in its "faded out" state — still taking up layout space but invisible.

If you want an exited element to actually be removed:

el.addEventListener('animationend', () => el.remove(), { once: true });

9.6 Never disable prefers-reduced-motion

The library automatically shortens animations to 1ms when the OS has "reduce motion" enabled. Do not override this. Users who enable reduced-motion typically do so because of a medical condition (vestibular disorders, seizure sensitivity).

Warning

Overriding the prefers-reduced-motion behavior to force animations is an accessibility violation. If an animation is load-bearing for UX (e.g., a page transition), make sure the non-animated state still communicates the change.

9.7 Inline elements do not animate

CSS animations on display: inline elements are undefined by spec — some browsers animate, some do not. If you want to animate a <span>, promote it to inline-block:

.badge { display: inline-block; }

Block-level elements, inline-block, flex / grid items, and table cells all animate reliably.


10. Accessibility

10.1 prefers-reduced-motion is built in

Animate.css honors the prefers-reduced-motion: reduce media query out of the box. When the user has requested reduced motion, all .animate__animated elements play at 1ms — effectively instantaneous — and iteration count is forced to 1.

The rule is applied at the @media print, (prefers-reduced-motion: reduce) level, so printed pages also skip animations.

10.2 What this means in practice

User setting What happens
Motion allowed Animations play normally
Reduced motion Animations complete in 1ms. Exit animations still leave the element invisible (opacity: 0).
Print Same as reduced motion — animations are effectively disabled

Tip

Test your site with reduced motion enabled. On macOS: System Settings -> Accessibility -> Display -> Reduce motion. On Windows: Settings -> Accessibility -> Visual effects -> Animation effects (off). On iOS: Settings -> Accessibility -> Motion -> Reduce Motion.


11. Troubleshooting

Error: The animation does nothing

Cause: Missing animate__animated. The animation classes only set animation-name — they need animate__animated to supply duration and fill-mode.

Solution: Add both classes: class="animate__animated animate__fadeIn".

Prevention: Treat the two-class pattern as a hard rule.

Error: The element disappears after an exit animation

Cause: Working as designed. animation-fill-mode: both holds the final keyframe state, which for exit animations is opacity: 0 plus an off-screen transform.

Solution: Remove the element on animationend, or remove the classes to reset visibility:

el.addEventListener('animationend', () => el.remove(), { once: true });

Error: The animation only plays once and I cannot replay it

Cause: The browser does not restart an animation when you re-add the same class — it sees no change.

Solution: Force a reflow between remove and add:

el.classList.remove('animate__animated', 'animate__bounce');
void el.offsetWidth;
el.classList.add('animate__animated', 'animate__bounce');

Error: Class names like bounce or fadeIn do not work

Cause: You are on v4+, which requires the animate__ prefix.

Solution: Either prefix every class (animate__bounce, animate__fadeIn) or switch the stylesheet you import from animate.min.css to animate.compat.css (compat ships the v3 unprefixed names).

Error: Animation causes horizontal / vertical scrollbars

Cause: Entrance and exit animations translate elements off-screen. Those off-screen frames are valid page content and the browser extends the scrollable area.

Solution: Add overflow: hidden to the nearest container that owns the animation:

.animation-wrapper { overflow: hidden; }

Warning

Do not put overflow: hidden on <body> unless you mean it — it prevents page scrolling.

Error: animate__shake does not work

Cause: In v4, shake was split into shakeX and shakeY. The original shake class is not included in animate.min.css.

Solution: Use animate__shakeX or animate__shakeY. If you must keep the old name, use animate.compat.css.

Error: animationend fires multiple times

Cause: The event bubbles up from every animated descendant. If you listen on a parent, you will see one event per child.

Solution: Call event.stopPropagation(), or check event.target === el, or attach the listener to the animated element itself.

Error: The flip animation only animates partially

Cause: flip briefly translates the element +150px on the Z axis using perspective(400px). A transform-style: flat on an ancestor or overflow: hidden on a small container can clip or flatten it.

Solution: Make sure you are using both classes (animate__animated animate__flip), and check that the parent does not clip 3D transforms.

Error: animate__infinite ignores my --animate-repeat override

Cause: Intentional. animate__infinite sets animation-iteration-count: infinite as a literal value; it does not reference the custom property.

Solution: Use animate__repeat-1, animate__repeat-2, or animate__repeat-3 and override --animate-repeat. For truly infinite animation, the only option is animate__infinite.

Error: The animation works in Chrome but not in Safari / Firefox

Cause: Almost always the prefers-reduced-motion setting. Safari and Firefox respect the OS setting; if you have "Reduce Motion" enabled system-wide, animations complete in 1ms.

Solution: Check your OS motion settings. The behavior is correct and by design.

Error: Bundler can't find animate.css when I import 'animate.css'

Cause: Some bundlers need an explicit file extension or require the file inside the package.

Solution: Try import 'animate.css/animate.min.css'; or reference the path from node_modules/animate.css/animate.min.css.

Error: The hinge animation falls on top of other content

Cause: By design — hinge ends at translate3d(0, 700px, 0) with opacity: 0, but the layout still reserves the element's original box. During the 2s animation the falling element may cover whatever is beneath it.

Solution: Wrap the hinging element in an absolutely positioned container, or remove the element on animationend.

Error: Nothing animates inside Shadow DOM

Cause: Animate.css is applied as a global stylesheet. Shadow DOM encapsulation isolates styles.

Solution: Import the stylesheet inside the shadow root, or adopt a CSSStyleSheet with adoptedStyleSheets.

Error: My content clipped during animate__flipInX

Cause: flipInX uses perspective(400px) rotation from 90deg. Parent containers with overflow: hidden or no room for the rotated bounding box can clip the element mid-rotation.

Solution: Give the container enough space (or temporarily remove overflow: hidden during the animation), or pick a gentler animation (fadeIn, slideInDown).

Tip

For a loading-on-page-load issue (#1856), ensure the <link> for animate.css is in <head> (blocking render is fine — the file is small), not in <body>. This prevents the element from rendering before the animation stylesheet loads.


12. FAQ

Q: Does animate.css require JavaScript?

No. Adding the classes to an element in HTML is enough. JavaScript is only needed if you want to trigger animations on events, remove them afterwards, or chain them.

Q: Does it work with Tailwind / Bootstrap / Bulma / Foundation?

Yes. The animate__ prefix was introduced in v4 specifically to avoid class-name collisions. If you are still on v3 (or using animate.compat.css) and you see conflicts, switch to v4's prefixed build.

Q: How do I change only one animation's duration without affecting others?

Scope the override:

.my-element.animate__bounce { --animate-duration: 500ms; }

Or inline:

<div class="animate__animated animate__bounce" style="--animate-duration: 500ms;">

Q: Can I use animate.css with server-side rendering (Next.js, Nuxt, SvelteKit)?

Yes. The stylesheet is static CSS — it loads the same way your other global styles do. No hydration concerns.

Q: Is there a way to animate route transitions (SPA)?

There is no built-in routing integration, but animateCSS from section 4.4 returns a Promise that resolves on animationend. Use it to sequence "fade out -> change route -> fade in" (see section 7.4).

Q: Why does bounceIn finish faster than fadeIn?

bounceIn, bounceOut, flipOutX, and flipOutY set a custom animation-duration: calc(var(--animate-duration) * 0.75) on their class — they are deliberately 25% shorter than the default 1s so the spring feels springy.

Q: What is the difference between fadeInLeft and fadeInLeftBig?

The Big variants translate across the full viewport width (or height). Non-Big variants only translate 100% of the element itself.

Q: Can I cancel an animation partway through?

Yes — remove the animate__animated class (or the animation class). The element snaps to its current CSS state immediately. Use the animationcancel event to detect this programmatically.

Q: Does animate.css support right-to-left (RTL) languages?

Directional animations (*Left, *Right) refer to physical directions, not logical ones. If your UI is RTL, fadeInLeft still comes from the geometric left. If you need mirror behavior, swap the classes in your RTL stylesheet or use fadeIn (non-directional) where possible.

Q: How big is the production build?

animate.min.css is roughly 60 KB uncompressed and approximately 9 KB gzipped. If that is too heavy, build a custom version with only the animations you use — see the Admin Guide's Custom Builds section.

Q: Can I chain two animations on the same element?

Not simultaneously — the second class wins whichever sets animation-name last. Run them sequentially by listening for animationend and swapping classes:

el.classList.add('animate__animated', 'animate__fadeIn');
el.addEventListener('animationend', () => {
  el.classList.remove('animate__fadeIn');
  el.classList.add('animate__pulse', 'animate__infinite');
}, { once: true });

Q: Can I use it in a static email?

Most email clients strip <style> blocks and ignore @keyframes. Animations will not play in Gmail, Outlook, or any mobile mail client. The animated elements will appear in their final state.

Q: Is there an Intellisense / autocomplete plugin for my editor?

There is community interest (see issue #1855) but no official plugin. Most modern editors autocomplete from the loaded CSS once the stylesheet is imported into your project.


13. Reference Quick Card

Two-class recipe
  class="animate__animated animate__<NAME>"

Utility classes (stackable)
  Speed    : animate__slower  animate__slow  animate__fast  animate__faster
  Delay    : animate__delay-1s ... animate__delay-5s
  Repeat   : animate__repeat-1  animate__repeat-2  animate__repeat-3  animate__infinite

Custom properties (overridable)
  --animate-duration   default 1s
  --animate-delay      default 1s
  --animate-repeat     default 1

JS events on animated element
  animationstart     animationiteration     animationend     animationcancel

Accessibility
  Respects @media (prefers-reduced-motion: reduce) — animations become 1ms.
  Never disable this.

Totals
  97 animations in 16 categories.
  3 custom properties.
  5 speed utilities, 5 delay utilities, 4 repeat utilities.