Documentation
Configuration
Define animation tokens, presets, diagnostics, reduced-motion policy, plugins, and the adapter target in one typed file.
Configuration
Motionwind uses a single configuration file at your project root. It defines animation tokens, reusable presets, strict diagnostics, and accessibility policy.
The config file
Create motionwind.config.ts at your project root:
import { defineConfig } from "motionwind-core";
export default defineConfig({
adapter: "react",
strict: true,
reducedMotion: "user",
tokens: {
durations: { fast: 160, deliberate: 480 },
easings: { product: [0.22, 1, 0.36, 1] },
springs: { responsive: { stiffness: 420, damping: 28 } },
},
presets: {
"card-enter":
"animate-initial:opacity-0 animate-enter:opacity-100 animate-duration-deliberate",
},
});Configuration options
adapter
Which framework you're using. Determines how the compiler and runtime behave.
adapter: "react" | "vue" | "vanilla" | "react-native";strict
When true, unknown animation classes and invalid syntax produce errors
instead of warnings. Recommended for CI.
strict: true;What strict catches:
- Unknown gesture prefixes (e.g.,
animate-invalid:scale-105) - Unknown property names (e.g.,
animate-hover:invalid-prop) - Invalid extension syntax
- Unknown preset names
reducedMotion
Controls what happens when the user's OS prefers reduced motion.
reducedMotion: "user" | "always" | "never";| Value | Behavior |
|---|---|
"user" | Respect the OS prefers-reduced-motion setting |
"always" | Always disable animations regardless of OS preference |
"never" | Never reduce motion regardless of OS preference |
Always use "user" unless you have a documented reason to override it.
Tokens
Tokens are named values you reference in classes. They keep your animation vocabulary consistent across the codebase.
Duration tokens
Map short names to millisecond values:
tokens: {
durations: {
fast: 160, // animate-duration-fast → 160ms
normal: 240, // animate-duration-normal → 240ms
deliberate: 480, // animate-duration-deliberate → 480ms
slow: 720, // animate-duration-slow → 720ms
},
}Usage:
<button class="animate-hover:scale-105 animate-duration-fast">Fast</button>
<article class="animate-enter:opacity-100 animate-duration-deliberate">
Slow
</article>Easing tokens
Map names to cubic-bezier curves or easing functions:
tokens: {
easings: {
product: [0.22, 1, 0.36, 1], // custom cubic-bezier
"ease-in-out": "ease-in-out", // named easing
},
}Usage:
<div class="animate-hover:x-10 animate-ease-product">Custom easing</div>Spring tokens
Map names to spring physics configurations:
tokens: {
springs: {
responsive: { stiffness: 420, damping: 28 }, // fast response
bouncy: { stiffness: 300, damping: 10 }, // bouncy feel
gentle: { stiffness: 120, damping: 20 }, // gentle settle
},
}Usage:
<button class="animate-hover:scale-105 animate-spring-responsive">
Responsive
</button>
<div class="animate-tap:scale-95 animate-spring-bouncy">Bouncy</div>Presets
Presets are reusable animation classes defined as a string of animate-*
tokens:
presets: {
"card-enter":
"animate-initial:opacity-0 animate-enter:opacity-100 animate-duration-deliberate",
"button-press":
"animate-tap:scale-95 animate-spring-responsive",
"list-stagger":
"animate-initial:opacity-0 animate-initial:y-10 animate-enter:opacity-100 animate-enter:y-0 animate-stagger-50",
}Usage:
<article class="animate-preset-card-enter">Fades in on mount</article>
<button class="animate-preset-button-press">Presses on tap</button>Passing config to frameworks
Each framework receives the config differently.
Next.js
// next.config.mjs
import { withMotionwind } from "motionwind-react/next";
import motionwindConfig from "./motionwind.config";
export default withMotionwind({}, motionwindConfig);React + Vite
// vite.config.ts
import { motionwind } from "motionwind-react/vite";
import motionwindConfig from "./motionwind.config";
export default defineConfig({
plugins: [motionwind(motionwindConfig), react()],
});Vue + Vite
// vite.config.ts
import {
createMotionwindTransform,
MotionwindPlugin,
} from "motionwind-vue/vite";
import motionwindConfig from "./motionwind.config";
export default defineConfig({
plugins: [
createMotionwindTransform(motionwindConfig),
vue(),
MotionwindPlugin(motionwindConfig),
],
});Vanilla JavaScript
import { motionwind } from "motionwind-vanilla";
import motionwindConfig from "./motionwind.config";
motionwind({ config: motionwindConfig });React Native / Expo
import { MotionwindProvider } from "motionwind-react-native";
import motionwindConfig from "./motionwind.config";
<MotionwindProvider config={motionwindConfig}>
<App />
</MotionwindProvider>;Plugins
Plugins extend Motionwind with custom properties, presets, and diagnostics:
import { defineMotionwindPlugin } from "motionwind-core";
const myPlugin = defineMotionwindPlugin({
name: "my-plugin",
version: "1.0.0",
core: ">=2 <3",
presets: {
"my-enter": "animate-enter:opacity-100 animate-duration-fast",
},
definitions: [
{
id: "my.custom",
category: "property",
label: "custom-",
snippet: "custom-${1:100}",
description: "A custom property.",
},
],
});Add plugins to your config:
export default defineConfig({
adapter: "react",
plugins: [myPlugin],
});Full example
Here's a complete config for a React project:
import { defineConfig } from "motionwind-core";
export default defineConfig({
adapter: "react",
strict: true,
reducedMotion: "user",
tokens: {
durations: {
fast: 160,
normal: 240,
deliberate: 480,
},
easings: {
product: [0.22, 1, 0.36, 1],
},
springs: {
responsive: { stiffness: 420, damping: 28 },
bouncy: { stiffness: 300, damping: 10 },
},
},
presets: {
"card-enter":
"animate-initial:opacity-0 animate-enter:opacity-100 animate-duration-deliberate",
"button-press": "animate-tap:scale-95 animate-spring-responsive",
},
});This gives you these classes:
| Class | Resolves to |
|---|---|
animate-duration-fast | transition.duration: 0.16 |
animate-ease-product | transition.ease: [0.22, 1, 0.36, 1] |
animate-spring-responsive | transition: { type: "spring", stiffness: 420, damping: 28 } |
animate-preset-card-enter | Fades in from opacity 0 with deliberate timing |
animate-preset-button-press | Scales to 95% with responsive spring |