tailwind-animates
v1.0.1
Published
animate.css as a Tailwind plugin with customizable animations and vendor prefixes
Readme
tailwind-animates
Use animate.css as a Tailwind 3 plugin with customizable animations and vendor prefixes.
Demo – https://dumptyd.github.io/tailwind-animates
Table of contents
Installation
yarn add tailwind-animates animate.css
# OR
npm install tailwind-animates animate.cssNote: This plugin uses animatecss-postcss-plugin as a dependency for CSS processing and vendor prefix management. It will be installed automatically with tailwind-animates.
Specify the plugin in tailwind.config.js
module.exports = {
// ...
plugins: [
require('tailwind-animates')
],
// ...
};Usage
Animations can be applied using animatecss prefixed classes:
<h1 class="animatecss animatecss-bounce">Bouncy!</h1>
<h1 class="animatecss animatecss-slideInDown">Sliding in</h1>
<h1 class="animatecss animatecss-jackInTheBox">Jack in the box</h1>All animate.css classes are modified to use the animatecss class name and prefix to avoid conflicts with Tailwind's animations. The table below should give you an idea of how the classes are mapped to the prefix.
| animate.css | tailwind-animates |
| - | - |
| animate__animated | animatecss |
| animate__fadeIn | animatecss-fadeIn |
| animate__infinite | animatecss-infinite |
| animate__repeat-2 | animatecss-repeat-2 |
| animate__delay-2s | animatecss-delay-2s |
| animate__fast | animatecss-fast |
| | ... and so on |
Configuration Options
You can customize the plugin behavior by passing an options object when requiring it.
Filtering animations
Reduce your CSS bundle size by including only the animations you need:
module.exports = {
plugins: [
require('tailwind-animates')({
classes: ['bounce', 'fadeIn', 'fadeOut', 'slideInUp']
})
]
};This will only include the specified animations, resulting in a smaller CSS output.
Customizing animation properties
Override default animation properties globally:
module.exports = {
plugins: [
require('tailwind-animates')({
duration: '2s', // Change default animation duration
delay: '500ms', // Add default delay
iterationCount: 'infinite' // Make animations repeat infinitely
})
]
};All available options
module.exports = {
plugins: [
require('tailwind-animates')({
prefix: 'animate', // Custom class prefix (default: 'animatecss')
classes: ['bounce', 'fadeIn', 'slideIn'], // Filter specific animations (default: all)
duration: '1.5s', // Default animation duration (default: from animate.css)
delay: '200ms', // Default animation delay (default: from animate.css)
iterationCount: '2' // Default iteration count (default: from animate.css)
})
]
};Example with multiple options:
module.exports = {
plugins: [
require('tailwind-animates')({
prefix: 'animate',
classes: ['bounce', 'fadeIn', 'fadeOut', 'slideInUp', 'zoomIn'],
duration: '1s',
iterationCount: '2'
})
]
};
// Usage in HTML:
// <h1 class="animate animate-bounce">Bouncy!</h1>Note: The plugin is fully backward compatible. If you don't pass any options, it works exactly as before with all animations included and default settings.
How Options Flow Internally
Understanding how your configuration is processed can help you use the plugin more effectively.
When you configure the plugin:
module.exports = {
plugins: [
require('tailwind-animates')({
prefix: 'animate',
classes: ['bounce', 'fadeIn', 'fadeOut', 'slideInUp'],
duration: '1.5s',
delay: '200ms',
iterationCount: '2'
})
]
};Internal processing flow:
- Main package receives your options and creates a config object
- Options are distributed to internal processing functions:
prefixandclasses→ Filter and customize animation utilitiesduration,delay,iterationCount→ Override CSS variables
- CSS processing through
postcss-preset-env(dependency):- Adds vendor prefixes for cross-browser compatibility
- Transforms modern CSS features
- Optimizes animation properties
- Final output → Tailwind-ready CSS utilities
Role separation:
| Component | Responsibility | |-----------|----------------| | tailwind-animates (main) | Filters animations, sets prefix, manages CSS variables | | postcss-preset-env (dependency) | Vendor prefixes, CSS transformation, optimization |
Benefits:
- ✅ Single configuration point for all options
- ✅ Automatic propagation to internal dependencies
- ✅ Clean, professional API
- ✅ Each package handles its specific domain
Advanced
Changing the prefix
By default, animatecss is used as the base class name and prefix for classes. This can be changed in two ways:
Option 1: Using plugin options (recommended)
module.exports = {
plugins: [
require('tailwind-animates')({
prefix: 'custom-animation'
})
]
};
// class names will now be available under
// `custom-animation`, `custom-animation-bounce`, `custom-animation-infinite` and so on.Option 2: Using theme configuration
module.exports = {
// ...
theme: {
animatecss: {
prefix: 'custom-animation'
}
}
// ...
};
// class names will now be available under
// `custom-animation`, `custom-animation-bounce`, `custom-animation-infinite` and so on.Note: Plugin options take precedence over theme configuration.
How this plugin differs from other implementations
Unlike other projects, this plugin doesn't implement the animations through a rewrite of the animate.css utilities.
Instead, classes, keyframes and styles are read from your installed version of animate.css at compile time and these are registered with Tailwind so the animations can be used with purging support, IntelliSense and other Tailwind goodness.
Contributing
https://github.com/dumptyd/tailwind-animates/issues
For Developers & Contributors
Project Structure
Directory Layout
tailwind-animates/
├── postcss-preset-env/ ← Custom dependency package
│ ├── index.js ← PostCSS plugin implementation
│ ├── package.json ← Package metadata
│ └── README.md ← Documentation
│
├── plugin.js ← Main plugin file
├── package.json ← Main package metadata
└── README.md ← This filePackage Responsibilities
Main Package (plugin.js)
Role: Tailwind CSS plugin that integrates animate.css
Responsibilities:
- ✅ Receives user configuration
- ✅ Filters animations by class names
- ✅ Sets custom prefix for classes
- ✅ Manages CSS variable overrides
- ✅ Registers utilities with Tailwind
- ✅ Orchestrates CSS processing
Key Functions:
main() // Entry point, receives Tailwind API
processVars() // Handles CSS variables
processUtilities() // Processes base utilities
processAnimations() // Processes animation classes
getStylesObjFromPath() // Reads and transforms CSS filesDependency Package (postcss-preset-env/)
Role: PostCSS plugin for CSS processing
Responsibilities:
- ✅ Receives options from main package
- ✅ Injects custom CSS variables
- ✅ Adds vendor prefixes to animations
- ✅ Processes @keyframes rules
- ✅ Ensures browser compatibility
Key Hooks:
Root() // Processes :root rules, injects variables
Declaration() // Adds vendor prefixes to properties
AtRule() // Processes @keyframes and other at-rulesImplementation Flow
Complete Data Flow
User Configuration (tailwind.config.js)
↓
┌─────────────────────────────────────────┐
│ Main Package (plugin.js) │
│ │
│ 1. Creates config object │
│ 2. Filters animations │
│ 3. Sets prefix │
│ 4. Prepares CSS variables │
└─────────────┬───────────────────────────┘
↓
getStylesObjFromPath({ config })
↓
┌─────────────────────────────────────────┐
│ Dependency Package │
│ (postcss-preset-env/index.js) │
│ │
│ 1. Receives config with user values │
│ 2. Injects CSS variables │
│ 3. Adds vendor prefixes │
│ 4. Processes @keyframes │
└─────────────┬───────────────────────────┘
↓
Processed CSS (ready for Tailwind)
↓
Tailwind CSS OutputStep-by-Step Processing
Step 1: User Configuration
// tailwind.config.js
module.exports = {
plugins: [
require('tailwind-animates')({
prefix: 'animate',
classes: ['bounce', 'fadeIn'],
duration: '1.5s', // ← User's value
delay: '200ms', // ← User's value
iterationCount: '2' // ← User's value
})
]
};Step 2: Main Package Creates Config Object
// Inside plugin.js - main() function
const config = {
prefix: 'animate', // ← Handled by main package
classes: ['bounce', ...], // ← Handled by main package
duration: '1.5s', // ↓ Passed to dependency
delay: '200ms', // ↓ Passed to dependency
iterationCount: '2' // ↓ Passed to dependency
};Step 3: Config Passed to Processing Functions
processVars(addUtilities, config); // ← config passed
processUtilities(addUtilities, config); // ← config passed
processAnimations(matchUtilities, config); // ← config passedStep 4: Functions Pass Config to getStylesObjFromPath
// Inside processVars, processUtilities, processAnimations
const rules = getStylesObjFromPath('source/_vars.css', {
config: {
duration: '1.5s', // ← Values forwarded
delay: '200ms', // ← Values forwarded
iterationCount: '2' // ← Values forwarded
}
});Step 5: getStylesObjFromPath Passes to postcss-preset-env
// Inside getStylesObjFromPath
if (config.duration || config.delay || config.iterationCount) {
const presetEnvOptions = {
stage: 3,
features: {
'custom-properties': {
preserve: true,
variables: {
'--animate-duration': config.duration || '1s', // ← '1.5s' passed
'--animate-delay': config.delay || '0s', // ← '200ms' passed
'--animate-repeat': config.iterationCount || '1' // ← '2' passed
}
}
},
autoprefixer: {
flexbox: 'no-2009',
grid: 'autoplace'
},
browsers: 'last 2 versions, > 1%, not dead'
};
// postcss-preset-env receives the actual user values!
const result = postcss([postcssPresetEnv(presetEnvOptions)]).process(cssString);
processedCss = result.css;
}Step 6: postcss-preset-env Processes CSS
/* Before (from animate.css) */
:root {
--animate-duration: 1s;
--animate-delay: 1s;
}
.animated {
animation-duration: var(--animate-duration);
animation-delay: var(--animate-delay);
}
/* After postcss-preset-env processing with user's values */
:root {
--animate-duration: 1.5s; /* ← User's value applied */
--animate-delay: 200ms; /* ← User's value applied */
--animate-repeat: 2; /* ← User's value applied */
}
.animatecss {
-webkit-animation-duration: var(--animate-duration); /* ← Vendor prefix added */
animation-duration: var(--animate-duration);
-webkit-animation-delay: var(--animate-delay); /* ← Vendor prefix added */
animation-delay: var(--animate-delay);
-webkit-animation-iteration-count: var(--animate-repeat); /* ← Vendor prefix added */
animation-iteration-count: var(--animate-repeat);
}What postcss-preset-env Does
| User Input | postcss-preset-env Action |
|------------|---------------------------|
| duration: '1.5s' | Applies to --animate-duration CSS variable + adds -webkit- prefix |
| delay: '200ms' | Applies to --animate-delay CSS variable + adds -webkit- prefix |
| iterationCount: '2' | Applies to --animate-repeat CSS variable + adds -webkit- prefix |
| (all values) | Optimizes for browser compatibility (last 2 versions) |
| (all values) | Transforms modern CSS features to work in older browsers |
Architecture Benefits
✅ Separation of Concerns
- Main package: Tailwind integration logic
- Dependency package: CSS processing logic
✅ Single Responsibility
- Each package has ONE clear purpose
- Easier to test and maintain
✅ Clean API
- User configures once
- Options flow automatically
✅ Professional Architecture
- Follows industry standards
- Modular and scalable
- Easy to extend
✅ Local Control
- You own the dependency code
- No reliance on external npm package
- Full customization freedom
Testing Strategy
Main Package Tests
- Test animation filtering
- Test prefix customization
- Test config merging
- Test Tailwind integration
Dependency Package Tests
- Test CSS variable injection
- Test vendor prefix addition
- Test @keyframes processing
- Test edge cases
Future Enhancements
Possible additions to the dependency package:
- Browser-specific optimizations
- Minification options
- Source map generation
- Custom transform plugins
- Performance optimizations
Contributing
https://github.com/dumptyd/tailwind-animates/issues
License
MIT
