Spring Animations
12 minSpring Animations
A spring animation simulates the physics of a real spring—an object pulled toward a target, slowed by friction, settling at rest. Unlike duration-based animations (which complete in a fixed time with a fixed curve), springs settle naturally based on physical parameters. They feel alive in ways that cubic-bezier curves cannot.
The difference is subtle in simple fades and dramatic in anything involving gesture. Drag a panel and release it with a cubic-bezier transition, and it completes in exactly 200ms regardless of how fast you flicked it. Do the same with a spring, and the panel carries your momentum—flick hard and it overshoots, drag gently and it settles smoothly. The physics respond to the user's input, which is why springs are the correct tool for any animation that follows direct manipulation.
The three parameters
Every spring is defined by three values. Understanding what each controls—and what happens when you push it too far—is the difference between a spring that feels natural and one that feels like a broken slinky.
Stiffness controls speed. Higher stiffness means the spring pulls harder toward its target, reaching it faster. Think of stiffness as the "urgency" of the animation. A stiffness of 100 is lazy and drifting. A stiffness of 500 is snappy and decisive. Above 700, the spring is so fast it starts to feel like a hard snap rather than a spring.
Damping controls resistance. Lower damping means less friction, which means more oscillation—the element overshoots its target and bounces back before settling. A damping of 15 gives a visible bounce. A damping of 40 gives a smooth settle with no perceptible overshoot. Think of damping as the "sobriety" of the animation—low damping is playful, high damping is professional.
Mass controls weight. Higher mass means the element feels heavier—it takes longer to get moving and longer to stop. A mass of 0.5 feels light and zippy. A mass of 2 feels like dragging a heavy drawer. Most UI elements should stay between 0.5 and 1.5. Above 2, the animation feels sluggish regardless of stiffness and damping.
Useful presets
Rather than tuning parameters from scratch every time, start with one of these presets and adjust:
| Preset | Stiffness | Damping | Use case | |---|---|---|---| | Snappy | 500 | 40 | General UI—no bounce, fast settle | | Bouncy | 300 | 20 | Playful elements, notification badges | | Gentle | 200 | 30 | Page transitions, large panels | | Stiff | 700 | 50 | Small precise movements, toggle switches |
Keep bounce subtle. In product interfaces, a bounce value (Apple's parameterisation) of 0.1–0.3 is appropriate. Anything above 0.3 reads as cartoonish outside of games and marketing sites.
The Apple-style parameterisation
Apple's animation system uses duration and bounce instead of stiffness, damping, and mass. This is often easier to reason about because duration maps directly to how long the animation takes, and bounce maps directly to how much overshoot occurs.
bounce: 0— no overshoot, smooth deceleration (equivalent to a critically damped spring)bounce: 0.15— barely perceptible settle, feels naturalbounce: 0.3— visible overshoot, playful but restrained
Framer Motion supports both parameterisations. Use whichever model makes the intent clearer to the next developer who reads the code.
Interruptibility—the killer feature
The real reason springs matter isn't aesthetics. It's interruptibility.
When a user triggers a CSS keyframe animation and then reverses their action mid-flight—opening a dropdown and immediately closing it, or swiping a panel partway and changing direction—the keyframe restarts from zero. The animation jumps to its initial state and plays the reverse sequence from the beginning, creating a visual discontinuity that feels broken.
A spring maintains its current velocity when retargeted. If the element is moving left at 400px/s and the user reverses direction, the spring smoothly decelerates, stops, and accelerates in the new direction—exactly like a physical object would. There's no jump, no restart, no discontinuity.
This is why every drag interaction, every gesture-driven UI, and every element that can be interrupted should use spring animations. The physics guarantee smooth retargeting, which CSS transitions and keyframes fundamentally cannot provide.
Rapid click both!
transition: transform 300ms ease-out{ type: 'spring', stiffness: 300, damping: 24 }When not to use springs
Springs are not universally superior. Skip them for:
- Simple opacity fades. A linear or ease-out fade is cleaner—springs can cause opacity to overshoot past 1.0, which is invisible but wastes frames.
- Colour transitions. Colour interpolation with spring overshoot produces values outside the intended palette. Use linear.
- Progress bars. A spring that bounces at 100% looks dishonest.
- Anything needing precise timing. If you need an animation to complete in exactly 200ms (for synchronisation with audio, video, or another animation), use a duration-based curve. Springs settle when the physics say so, not when a timer expires.
In code
import { motion } from "motion/react"
// Stiffness/damping/mass parameterisation
<motion.div
animate={{ x: isOpen ? 300 : 0 }}
transition={{ type: "spring", stiffness: 500, damping: 40 }}
/>
// Apple-style parameterisation
<motion.div
animate={{ x: isOpen ? 300 : 0 }}
transition={{ type: "spring", duration: 0.4, bounce: 0.15 }}
/>
The choice between the two is a matter of intent. Stiffness/damping gives you precise control. Duration/bounce gives you predictable timing with natural motion. Use the one that makes the animation's purpose clearest.