Back to Blogs
Next

Understanding Motion (Framer Motion) Spring Animations

A deep dive into spring physics in Motion (formerly Framer Motion) and how to create natural, buttery-smooth interactions.

When it comes to web animations, traditional CSS easing functions like ease-in or ease-out are often the default choice. However, they rely on fixed durations, which can make them feel rigid, mechanical, and disconnected from the real world.

Enter Spring Physics.

Springs are fundamentally different. Instead of animating over a set time, they simulate physical properties like mass, stiffness, and damping. This creates animations that feel organic, tactile, and buttery-smooth. With the library Motion (formerly Framer Motion), implementing spring physics is incredibly straightforward.

Why Use Springs?

In the real world, objects don't move with perfect, linear precision. They carry momentum, they overshoot, and they bounce depending on their weight and the friction of their environment.

When you use a spring, you are describing the environment of the animation rather than the duration. This solves a few critical problems:

  1. Fluid Interruption: If a user clicks a button halfway through its hover animation, a time-based tween has to awkwardly calculate a new path and duration. A spring simply redirects the momentum seamlessly, exactly like a physical object.
  2. Natural Feel: Elements feel like they have weight. A heavy modal dialog can drop in with a thud, while a lightweight tooltip can pop in quickly.
  3. Less Guesswork: You don't have to fiddle with 0.3s vs 0.4s or complex bezier curves. You just tweak physical properties until it feels right.

The Core Properties of a Spring

Motion allows you to define a spring transition by simply setting type: "spring". To control the feel of the spring, you primarily adjust three properties:

1. Stiffness (default: 100)

Stiffness determines how "tight" or "strong" the spring is. A higher stiffness means the animation will move faster and snap to its destination more aggressively.

  • Low (50): Loose and slow.
  • High (500): Snappy and fast.

2. Damping (default: 10)

Damping acts as friction. It determines how quickly the spring stops bouncing.

  • Low (0–5): Very bouncy, like a yo-yo.
  • High (20+): Little to no bounce. If damping is high enough, the spring won't bounce at all — this is called a critically damped spring.
  • Zero (0): The spring oscillates forever. Avoid this in UI unless you explicitly want a looping pulse effect.

3. Mass (default: 1)

Mass represents the "weight" of the object being animated. A heavier object takes longer to get moving and longer to stop.

  • Low (0.5): Very light, quick to start and stop.
  • High (5): Heavy, sluggish to start, carries a lot of momentum.

Interactive Spring Visualizer

To truly understand how these properties interact, the best way is to play with them. Use the visualizer below to adjust Stiffness, Damping, and Mass and see how it affects the curve and the resulting animation. Copy the config directly into your project when it feels right.

400
10
1.0

Basic Usage in Motion

Here is how you can implement a basic spring animation on a button hover or tap state:

Notice how we don't define a duration. The animation takes exactly as long as the physics dictate.

The bounce and duration Shorthand

If tweaking mass and stiffness feels too scientific, Motion provides an alternative, more intuitive API using bounce and duration.

  • bounce (0 to 1): Determines how bouncy the spring is. 0 means no bounce, 1 means highly bouncy.
  • duration (in seconds): The approximate time it takes for the animation to settle.
<motion.div
  initial={{ y: 50, opacity: 0 }}
  animate={{ y: 0, opacity: 1 }}
  transition={{
    type: "spring",
    bounce: 0.4,
    duration: 0.8,
  }}
>
  I'm a card dropping in!
</motion.div>

Under the hood, Motion calculates the appropriate stiffness, damping, and mass to achieve this bounce and duration. This is often the best way to get started.

Settling: restDelta and restSpeed

By default, Motion considers a spring "at rest" when its position and velocity fall below a small built-in threshold. You can override both with restDelta and restSpeed.

  • restDelta — how close to the target (in px) the spring must be before it snaps.
  • restSpeed — how slow (in px/s) the spring must be moving before it stops.
transition={{
  type: "spring",
  stiffness: 200,
  damping: 20,
  restDelta: 0.01,  // snap when within 0.01px of target
  restSpeed: 0.5,   // snap when moving slower than 0.5px/s
}}

Lowering both makes the spring settle more precisely — useful for pixel-perfect layout animations. Raising them makes it snap earlier, which can feel snappier on cheap hardware at the cost of a tiny visual jump.

useSpring — Springs as Live Values

Everything above applies to one-shot animate transitions. But Motion also exposes useSpring, which turns a MotionValue into a spring-smoothed version of it. This is how you build cursor followers, scroll-linked parallax, and drag-snap effects — things that need to react continuously to live input rather than animate between two fixed states.

Move cursor here

The key insight: mouseX and mouseY update instantly on every mousemove. smoothX and smoothY chase them with spring physics — no animate call, no keyframes, just continuous physical simulation driven by live values.

You can also initialize useSpring from a static number:

const scale = useSpring(1, { stiffness: 300, damping: 20 });
 
// Later, in an event handler:
scale.set(1.2); // springs to 1.2
scale.set(1); // springs back

Velocity-Preserving Interruption

This is where springs genuinely beat CSS transitions. When you change a spring's target mid-animation, it doesn't reset — it redirects from wherever it currently is, carrying its current velocity.

Tween Animation

Rapid clicks cause abrupt direction changes because every animation restarts with a fresh easing curve.

Spring Animation

Rapid clicks preserve momentum. The box smoothly redirects while carrying its existing velocity into the new direction.

Spam the buttons rapidly. The difference becomes obvious when animations are interrupted before they finish.

Spam the buttons rapidly and compare both rows. The tweened animation recalculates a brand-new easing curve on every interruption, which makes direction changes feel abrupt. The spring, however, preserves its current velocity and smoothly redirects momentum into the new direction — making the interaction feel continuous, responsive, and physical.

Common Presets

These are battle-tested starting points. Paste them in and tweak from there.

Use caseStiffnessDampingMassNotes
Modal / sheet enter300301No bounce, fast settle
Tooltip / popover500250.5Light and snappy
Drag snap-back200201.2Carries drag momentum
Cursor follower400300.5Tight but smooth
Hero text drop-in120141Gentle bounce
Bouncy button600120.8Playful overshoot

When Not to Use Springs

Springs are not universally better. A few cases where they hurt more than they help:

  • opacity and color — these properties don't have physical analogues. A bouncing fade-in looks broken, not natural. Use ease-out with a short duration instead.
  • layout animations on text — spring-driven layout shifts on reflow-heavy text containers can cause jank on low-end devices. Prefer ease with layout prop.
  • Looping animations — springs settle; they're not designed for repeat: Infinity. Use a keyframe tween for spinners, pulses, and marquees.
  • Reduced motion — always check prefers-reduced-motion. A user who has enabled this setting finds bouncy animations actively uncomfortable. Fade to a simple opacity tween in that case.
const prefersReduced = window.matchMedia(
  "(prefers-reduced-motion: reduce)",
).matches;
 
const transition = prefersReduced
  ? { duration: 0.15, ease: "easeOut" }
  : { type: "spring", stiffness: 400, damping: 25 };

Real-World Applications

Springs aren't just for playful, bouncy UI. They are essential for creating professional, premium interfaces.

  • Modals and Drawers: Use a critically damped spring (high stiffness, high damping) to make a drawer slide in quickly without bouncing, but with a smooth deceleration.
  • Drag Interactions: When dragging a card (like a Tinder swipe), the card should return to the center with a spring. By passing the drag velocity into the spring, the card preserves the momentum of the user's swipe, creating a hyper-realistic physical interaction.
  • Micro-interactions: Tooltips, toggles, and dropdowns feel much more satisfying with a subtle, quick spring rather than a linear fade.

Conclusion

Once you start using spring physics, it's hard to go back to standard CSS transitions. By shifting your mindset from "how long should this take" to "how heavy should this feel", you can elevate your web interfaces from feeling like static websites to feeling like native applications.

The three things worth internalizing: use type: "spring" with stiffness/damping/mass for one-shot animations, reach for useSpring whenever you need to smooth live input values, and always gate bouncy springs behind a prefers-reduced-motion check.