Documentation
Introduction
motionwind lets you write Motion animations as Tailwind-like utility classes, compiled away at build time.
motionwind
motionwind brings the expressiveness of Motion (formerly Framer Motion) into the Tailwind CSS mental model. Instead of writing verbose JSX props, you declare animations as familiar utility classes directly in your className string.
A Babel plugin runs at build time, finds every animate-* class, parses them into Motion props, and rewrites the element as a motion.* component -- all before your code ever reaches the browser.
<div className="animate-hover:scale-110 animate-tap:scale-90 animate-spring">
Hover or tap me
</div>At build time, that single line becomes:
<motion.div
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
transition={{ type: "spring" }}
>
Hover or tap me
</motion.div>You never import motion, you never write prop objects, and the transform disappears from your production bundle.
Why motionwind?
Zero runtime overhead
The Babel plugin does all the work at compile time. There is no extra runtime parser shipping with your app. The animate-* classes are consumed entirely by the transform and do not appear in the final CSS or HTML output. What ships to the browser is plain Motion code.
Familiar syntax
If you know Tailwind, you already know motionwind. The class pattern is animate-{gesture}:{property}-{value}. Gestures like hover, tap, focus, and inview map directly to Motion's whileHover, whileTap, whileFocus, and whileInView. Properties like scale, rotate, x, y, and opacity work exactly as you would expect.
Colocation
Animations live right next to the styles they modify. No separate animation files, no variant objects to define elsewhere. A single className string describes the element's visual appearance, layout, and motion behavior.
Full Motion power
motionwind supports gestures, scroll-triggered animations, enter/exit transitions, spring physics, drag, viewport detection, repeating animations, and arbitrary Motion properties via bracket syntax. Anything you can do with Motion, you can express as a class.
Core concepts
Gesture prefixes
Every animation class starts with animate- followed by a gesture prefix and a colon:
animate-hover:-- runs while the pointer is over the elementanimate-tap:-- runs while the element is pressedanimate-focus:-- runs while the element has keyboard focusanimate-inview:-- runs when the element enters the viewportanimate-drag:-- runs while the element is being draggedanimate-initial:-- the starting state before the enter animationanimate-enter:-- the target state for mount/entrance animationsanimate-exit:-- the state to animate to when the element unmounts
Animatable properties
After the gesture prefix, you specify a property and value:
- Transform:
scale,scale-x,scale-y,rotate,rotate-x,rotate-y,skew-x,skew-y,x,y - Visual:
opacity,blur,brightness,contrast,saturate - Layout:
w(width),h(height),rounded(border-radius)
Transition configuration
Global transition settings are written without a gesture prefix:
animate-duration-300-- 300ms durationanimate-ease-in-out-- easing functionanimate-spring-- spring physicsanimate-stiffness-200-- spring stiffnessanimate-repeat-3-- repeat 3 times
Dynamic classNames
The Babel plugin only transforms static string literals. For dynamic or conditional classNames, motionwind provides a runtime component API:
import { mw } from "motionwind-react";
<mw.button className={`animate-hover:scale-110 ${isActive ? "bg-blue-500" : "bg-gray-500"}`}>
Click
</mw.button>Next steps
- Getting Started -- understand how the build-time transform works
- Installation -- set up motionwind in your project
- Syntax Reference -- complete guide to every class and option