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.

Hover to Stretch Horizontally
<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.

Hover to Stretch Vertically
<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:

Tap to Squash
<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>
ClassCompiled Value
animate-hover:scale-z-50scaleZ: 0.5
animate-hover:scale-z-100scaleZ: 1
animate-hover:scale-z-120scaleZ: 1.2
animate-hover:scale-z-200scaleZ: 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].

Hover to Tilt Forward
<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.

Hover to Swing Open
<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>
ClassCompiled Value
animate-hover:skew-6skew: 6
animate-hover:skew-12skew: 12
animate-hover:-skew-12skew: -12
animate-hover:skew-45skew: 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.

Hover to Skew Horizontally
<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.

Hover to Skew Vertically
<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:

ClassCompiled Value
animate-hover:z-50z: 50
animate-hover:z-100z: 100
animate-hover:-z-50z: -50
animate-hover:-z-100z: -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

SuffixCSS UnitExample ClassCompiled Value
pct%x-100pctx: "100%"
pxpxx-50pxx: "50px"
vhvhx-50vhx: "50vh"
vwvwx-50vwx: "50vw"
remremx-3remx: "3rem"
ememx-2emx: "2em"
dvhdvhy-100dvhy: "100dvh"
svhsvhy-100svhy: "100svh"
lvhlvhy-100lvhy: "100lvh"
(none)autoy-autoy: "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

ValueoriginX / originYPosition
00Left / Top
250.25Quarter
500.5Center (default)
750.75Three-quarters
1001Right / 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>
ClassCompiled Value
animate-hover:origin-x-0originX: 0
animate-hover:origin-x-50originX: 0.5
animate-hover:origin-x-100originX: 1
animate-hover:origin-y-0originY: 0
animate-hover:origin-y-50originY: 0.5
animate-hover:origin-y-100originY: 1
animate-hover:origin-z-100originZ: 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>
ClassCompiled Value
animate-hover:perspective-400perspective: 400
animate-hover:perspective-800perspective: 800
animate-hover:perspective-1200perspective: 1200

Note: This is the Motion perspective prop on the animated element itself. For applying CSS perspective on a parent container (needed for rotateX/rotateY to 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.

Negative Transforms
<!-- 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:

ClassCompiled Value
animate-hover:rotate-45rotate: 45
animate-hover:-rotate-45rotate: -45
animate-hover:x-20x: 20
animate-hover:-x-20x: -20

Combined Transforms

Stack multiple transform classes on the same gesture to create rich, multi-axis effects.

3D Hover Card
<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 perspective to the parent container, not the animated element itself
Dramatic vs Subtle Perspective
<!-- 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.