Documentation
Transform Animations
Animate scaleX, scaleY, scaleZ, rotateX, rotateY, skewX, skewY, transform origin, perspective, Z-axis translation, and unit-based translate values for advanced 2D and 3D transform effects.
Beyond the basic scale and rotate shorthands, motionwind supports individual axis transforms for fine-grained control over 2D and 3D animations. These map directly to Motion's transform properties and are processed identically at build time.
ScaleX
Scale an element along the horizontal axis only. Values work the same as scale -- they are divided by 100, so scale-x-120 becomes scaleX: 1.2.
<div className="animate-hover:scale-x-120 animate-spring">X</div>Compiles to:
<motion.div
whileHover={{ scaleX: 1.2 }}
transition={{ type: "spring" }}
>
X
</motion.div>ScaleY
Scale an element along the vertical axis only. Use scale-y-120 to stretch it taller, or scale-y-50 to squash it.
<div className="animate-hover:scale-y-120 animate-spring">Y</div>Compiles to:
<motion.div
whileHover={{ scaleY: 1.2 }}
transition={{ type: "spring" }}
>
Y
</motion.div>Squash and Stretch
Combine scaleX and scaleY for classic squash-and-stretch effects:
<div className="animate-hover:scale-y-80 animate-hover:scale-x-120 animate-tap:scale-y-70 animate-tap:scale-x-130 animate-spring animate-stiffness-400 animate-damping-10">
Boing
</div>Compiles to:
<motion.div
whileHover={{ scaleY: 0.8, scaleX: 1.2 }}
whileTap={{ scaleY: 0.7, scaleX: 1.3 }}
transition={{ type: "spring", stiffness: 400, damping: 10 }}
>
Boing
</motion.div>ScaleZ
Scale an element along the Z-axis for 3D depth scaling. Like scaleX and scaleY, values are divided by 100, so scale-z-120 becomes scaleZ: 1.2. This is most useful in combination with perspective and other 3D transforms to create depth effects.
<div className="[perspective:800px]">
<div className="animate-hover:scale-z-120 animate-hover:rotate-y-20 animate-spring">
Depth
</div>
</div>Compiles to:
<div style={{ perspective: "800px" }}>
<motion.div
whileHover={{ scaleZ: 1.2, rotateY: 20 }}
transition={{ type: "spring" }}
>
Depth
</motion.div>
</div>| Class | Compiled Value |
|---|---|
animate-hover:scale-z-50 | scaleZ: 0.5 |
animate-hover:scale-z-100 | scaleZ: 1 |
animate-hover:scale-z-120 | scaleZ: 1.2 |
animate-hover:scale-z-200 | scaleZ: 2 |
RotateX
Rotate an element around the horizontal axis, creating a 3D tilt effect. The value is in degrees.
For the 3D effect to be visible, the parent element needs CSS perspective. You can set this with a Tailwind utility like [perspective:800px].
<div className="[perspective:800px]">
<div className="animate-hover:rotate-x-45 animate-spring">
Tilt X
</div>
</div>Compiles to:
<div style={{ perspective: "800px" }}>
<motion.div
whileHover={{ rotateX: 45 }}
transition={{ type: "spring" }}
>
Tilt X
</motion.div>
</div>RotateY
Rotate an element around the vertical axis. This creates a card-flip or door-swing type of 3D effect.
<div className="[perspective:800px]">
<div className="animate-hover:rotate-y-45 animate-spring">
Tilt Y
</div>
</div>Compiles to:
<div style={{ perspective: "800px" }}>
<motion.div
whileHover={{ rotateY: 45 }}
transition={{ type: "spring" }}
>
Tilt Y
</motion.div>
</div>Full Card Flip
Combine rotateY with initial and enter gestures for a card flip on load:
<div className="[perspective:1000px]">
<div className="animate-initial:rotate-y-180 animate-enter:rotate-y-0 animate-duration-800">
Flips in on mount
</div>
</div>Skew (Uniform)
Apply the same skew angle to both axes simultaneously. The value is in degrees. Use skew-12 to skew the element by 12 degrees on both the X and Y axes at once.
<div className="animate-hover:skew-12 animate-spring">Skew</div>Compiles to:
<motion.div
whileHover={{ skew: 12 }}
transition={{ type: "spring" }}
>
Skew
</motion.div>| Class | Compiled Value |
|---|---|
animate-hover:skew-6 | skew: 6 |
animate-hover:skew-12 | skew: 12 |
animate-hover:-skew-12 | skew: -12 |
animate-hover:skew-45 | skew: 45 |
If you need different skew values per axis, use the skew-x-{n} and skew-y-{n} classes below instead.
SkewX
Skew an element along the horizontal axis. The value is in degrees. This creates a slanted, italic-like distortion.
<div className="animate-hover:skew-x-12 animate-spring">Skew X</div>Compiles to:
<motion.div
whileHover={{ skewX: 12 }}
transition={{ type: "spring" }}
>
Skew X
</motion.div>SkewY
Skew an element along the vertical axis. This creates a leaning, parallelogram-like distortion.
<div className="animate-hover:skew-y-12 animate-spring">Skew Y</div>Compiles to:
<motion.div
whileHover={{ skewY: 12 }}
transition={{ type: "spring" }}
>
Skew Y
</motion.div>Z-Axis Translation
Translate an element along the Z-axis for 3D depth movement. The class z-{n} compiles to z: n in pixels. This requires a parent element with CSS perspective for the 3D effect to be visible.
<div className="[perspective:800px]">
<div className="animate-hover:z-50 animate-spring">
Come closer
</div>
</div>Compiles to:
<div style={{ perspective: "800px" }}>
<motion.div
whileHover={{ z: 50 }}
transition={{ type: "spring" }}
>
Come closer
</motion.div>
</div>Positive values move the element towards the viewer; negative values push it away:
| Class | Compiled Value |
|---|---|
animate-hover:z-50 | z: 50 |
animate-hover:z-100 | z: 100 |
animate-hover:-z-50 | z: -50 |
animate-hover:-z-100 | z: -100 |
Unit Values for Translate
The x, y, and z translate classes support unit suffixes that compile to string values with the corresponding CSS unit. By default, values are plain numbers (pixels), but appending a unit suffix produces a quoted string value.
Supported Unit Suffixes
| Suffix | CSS Unit | Example Class | Compiled Value |
|---|---|---|---|
pct | % | x-100pct | x: "100%" |
px | px | x-50px | x: "50px" |
vh | vh | x-50vh | x: "50vh" |
vw | vw | x-50vw | x: "50vw" |
rem | rem | x-3rem | x: "3rem" |
em | em | x-2em | x: "2em" |
dvh | dvh | y-100dvh | y: "100dvh" |
svh | svh | y-100svh | y: "100svh" |
lvh | lvh | y-100lvh | y: "100lvh" |
| (none) | auto | y-auto | y: "auto" |
Examples
Slide an element by a percentage of its own width:
<div className="animate-hover:x-100pct animate-spring">Slide right 100%</div>Compiles to:
<motion.div
whileHover={{ x: "100%" }}
transition={{ type: "spring" }}
>
Slide right 100%
</motion.div>Slide an element by a viewport unit:
<div className="animate-hover:x-50vh animate-spring">Slide 50vh</div>Compiles to:
<motion.div
whileHover={{ x: "50vh" }}
transition={{ type: "spring" }}
>
Slide 50vh
</motion.div>Negative Unit Values
Negative values work with unit suffixes using the - prefix:
<div className="animate-hover:-x-100pct animate-spring">Slide left 100%</div>Compiles to:
<motion.div
whileHover={{ x: "-100%" }}
transition={{ type: "spring" }}
>
Slide left 100%
</motion.div>Auto Value
The special value auto does not take a number and compiles to the string "auto":
<div className="animate-hover:y-auto animate-spring">Auto Y</div>Compiles to:
<motion.div
whileHover={{ y: "auto" }}
transition={{ type: "spring" }}
>
Auto Y
</motion.div>Transform Origin
Control the origin point of transform animations using origin-x-{n}, origin-y-{n}, and origin-z-{n}. The X and Y values range from 0 to 100 and are divided by 100 to produce a 0-1 decimal, matching Motion's originX and originY props. The Z value is in pixels and is not divided.
Common Origin Values
| Value | originX / originY | Position |
|---|---|---|
0 | 0 | Left / Top |
25 | 0.25 | Quarter |
50 | 0.5 | Center (default) |
75 | 0.75 | Three-quarters |
100 | 1 | Right / Bottom |
Rotate from Top-Left Corner
<div className="animate-hover:origin-x-0 animate-hover:origin-y-0 animate-hover:rotate-45 animate-spring">
Top-left pivot
</div>Compiles to:
<motion.div
whileHover={{ originX: 0, originY: 0, rotate: 45 }}
transition={{ type: "spring" }}
>
Top-left pivot
</motion.div>Rotate from Bottom-Right Corner
<div className="animate-hover:origin-x-100 animate-hover:origin-y-100 animate-hover:rotate-45 animate-spring">
Bottom-right pivot
</div>Compiles to:
<motion.div
whileHover={{ originX: 1, originY: 1, rotate: 45 }}
transition={{ type: "spring" }}
>
Bottom-right pivot
</motion.div>Origin Z
The origin-z-{n} class maps to originZ in pixels (not divided by 100). This shifts the transform origin along the Z-axis for 3D effects:
<div className="[perspective:800px]">
<div className="animate-hover:origin-z-100 animate-hover:rotate-y-30 animate-spring">
Z offset origin
</div>
</div>Compiles to:
<div style={{ perspective: "800px" }}>
<motion.div
whileHover={{ originZ: 100, rotateY: 30 }}
transition={{ type: "spring" }}
>
Z offset origin
</motion.div>
</div>| Class | Compiled Value |
|---|---|
animate-hover:origin-x-0 | originX: 0 |
animate-hover:origin-x-50 | originX: 0.5 |
animate-hover:origin-x-100 | originX: 1 |
animate-hover:origin-y-0 | originY: 0 |
animate-hover:origin-y-50 | originY: 0.5 |
animate-hover:origin-y-100 | originY: 1 |
animate-hover:origin-z-100 | originZ: 100 |
Perspective
Set the perspective Motion prop directly on the animated element. The class perspective-{n} compiles to perspective: n in pixels.
This is different from CSS perspective applied on a parent container. Motion's perspective prop applies perspective to the element's own transform, which can be useful when you want the element itself to control its 3D space.
<div className="animate-hover:perspective-800 animate-hover:rotate-y-30 animate-spring">
Self-perspective
</div>Compiles to:
<motion.div
whileHover={{ perspective: 800, rotateY: 30 }}
transition={{ type: "spring" }}
>
Self-perspective
</motion.div>| Class | Compiled Value |
|---|---|
animate-hover:perspective-400 | perspective: 400 |
animate-hover:perspective-800 | perspective: 800 |
animate-hover:perspective-1200 | perspective: 1200 |
Note: This is the Motion
perspectiveprop on the animated element itself. For applying CSS perspective on a parent container (needed forrotateX/rotateYto appear 3D), use a Tailwind utility like[perspective:800px]on the parent element. See the 3D Perspective Effects section below.
Negative Values
All transform properties support negative values using the - prefix. This flips the direction of the animation.
<!-- Rotate counter-clockwise -->
<div className="animate-hover:-rotate-45">-45</div>
<!-- Skew in the opposite direction -->
<div className="animate-hover:-skew-x-12">-Sk</div>
<!-- Slide left instead of right -->
<div className="animate-hover:-x-20">-X</div>The - prefix sets an internal negative flag that multiplies the parsed value by -1:
| Class | Compiled Value |
|---|---|
animate-hover:rotate-45 | rotate: 45 |
animate-hover:-rotate-45 | rotate: -45 |
animate-hover:x-20 | x: 20 |
animate-hover:-x-20 | x: -20 |
Combined Transforms
Stack multiple transform classes on the same gesture to create rich, multi-axis effects.
<div className="[perspective:800px]">
<div className="animate-hover:rotate-x-10 animate-hover:-rotate-y-10 animate-hover:scale-105 animate-spring">
3D hover card
</div>
</div>Compiles to:
<div style={{ perspective: "800px" }}>
<motion.div
whileHover={{ rotateX: 10, rotateY: -10, scale: 1.05 }}
transition={{ type: "spring" }}
>
3D hover card
</motion.div>
</div>3D Perspective Effects
For any rotateX or rotateY animation to look three-dimensional, you need CSS perspective on a parent element. Without it, the rotation will appear flat.
Tips for perspective values:
- Lower values (300-500px) create a more dramatic, exaggerated 3D effect
- Higher values (800-1200px) create a subtler, more realistic depth
- Apply
perspectiveto the parent container, not the animated element itself
<!-- Dramatic 3D -->
<div className="[perspective:300px]">
<div className="animate-hover:rotate-y-30">300px</div>
</div>
<!-- Moderate 3D -->
<div className="[perspective:600px]">
<div className="animate-hover:rotate-y-30">600px</div>
</div>
<!-- Subtle 3D -->
<div className="[perspective:1200px]">
<div className="animate-hover:rotate-y-30">1200px</div>
</div>All three elements use the same rotate-y-30 class, but the parent's perspective value controls how pronounced the 3D rotation appears.