Framer Motion Spring Presets: Stiffness and Damping

A framer motion spring is two numbers that decide how every press, toggle and popover in your app feels, and most codebases end up with dozens of them typed inline: stiffness: 400, damping: 17 here, 260 / 20 there, copied from whatever tutorial was open that day. This tutorial replaces that with four named presets, shows the real stiffness and damping values we ship in Wingo UI's motion presets, measures what each one does, and explains which UI gets which spring and how to share them across a whole component library.
The package is called motion now. The motion.dev upgrade guide (opens in a new tab) (checked October 2026) swaps framer-motion for motion and moves imports to motion/react; the spring options are the same, so a framer motion spring and a motion react spring transition take the same stiffness, damping and mass. Everything below uses motion 12.43.
How does a Framer Motion spring animation work?
A spring has no fixed duration. Motion simulates a mass on a spring: stiffness is how hard the spring pulls toward the target, damping is the friction that slows it down, and mass is how heavy the thing is (1 by default). The animation ends when the value is close enough to the target and slow enough to stop.
Two consequences matter for UI work:
- Feel comes from the ratio, not the raw numbers. The damping ratio is
damping / (2 * Math.sqrt(stiffness * mass)). Below 1 the value overshoots and swings back. At 1 or above it arrives without overshoot. Two springs with the same ratio feel like the same curve played at different speeds. - A spring keeps its speed when you retarget it. Motion's transition docs (opens in a new tab) say physics based springs incorporate the velocity of existing gestures or animations, and duration based ones do not. Tap a segmented control twice quickly and the thumb bends toward the new option instead of stopping and restarting.
You can check the ratio in one line:
Which stiffness and damping values should a UI use?
If you came for stiffness damping values to copy, these four, from lib/motion.ts in Wingo UI, are the only springs our components use:
We measured each one with motion's own spring() generator from motion-dom 12.43, animating a value from 0 to 100 with a mass of 1. "Within 1%" is the time after which the value stays within one unit of the target.
Read the table from the user's side, and note that settle time is not perceived speed. Snappy covers 90% of the distance in 120ms against 188ms for smooth, then spends the rest of its time on a 4% overshoot, which reads as the control reacting to the finger. Smooth settles slightly sooner overall with no visible overshoot, so a dialog opening never looks like it wobbles. Bouncy overshoots by a fifth, which is fun once on a success tick and tiring on every popover. Gentle takes about half a second and stays calm, which suits a whole chart growing in.
The last row is the trap. Write transition={{ type: "spring" }} with no numbers and motion falls back to stiffness 100 and damping 10: almost a second of settling and a 16% overshoot. Always pass a named preset.
The demo below doubles as a framer motion spring visualizer: four balls run the four springs side by side. Pick a spring in the playground controls, then replay the list to see it drive real rows.
$ npx wingo-ui@latest add motionWhat does each spring preset look like in real components?
Snappy for anything a finger touches
Every pressable surface in the library shares one press: scale to 0.97 on springs.snappy. The free Button spreads it from a single constant, and so can your own components:
The free Switch moves its thumb with animate(pos, checked ? 1 : 0, springs.snappy) on a motion value, and stretches the thumb on the same spring while it is held. The free Segmented Control slides its thumb on snappy too, and passes the current velocity of the thumb into the next animation, so a second tap mid-slide changes direction without a jolt:
$ npx wingo-ui@latest add segmented-controlThe React segmented control guide covers the rest of that control, from the draggable thumb to radio semantics.
Smooth as the default for overlays and layout
Dialogs, toasts, list rows and content swaps all enter on springs.smooth. Its 0.87 ratio overshoots 0.4%, which on a dialog rising 8px into place is a few hundredths of a pixel, so the surface lands softly without a visible wobble. Popovers and menus are the exception: their preset uses snappy, because they open in direct answer to a click. It is also the right spring for layout animations, where a bounce would make neighboring content shake.
Notice the exit: a short tween, not a spring. A quick exit reads as responsive and the entrance can take its time, so most presets in lib/motion leave in 150ms.
Bouncy for one accent per screen
Bouncy belongs where a little celebration is the point: the icon tile of an alert dialog pops in on { ...springs.bouncy, delay: 0.06 }, and a success check can do the same. Keep it off anything people open many times a day. The 20% overshoot that delights once becomes noise on the tenth menu.
Gentle for large surfaces
Big things should move slowly. Chart bars grow on springs.gentle with a small per-bar delay, and page sections reveal on it. At stiffness 120 the motion lasts about half a second and never overshoots visibly, so a 300px bar does not bounce past its value and misreport the data for a moment.
How do you share springs across a component library?
Put them in one file and import them everywhere. Three habits keep that file the only source of spring numbers:
- Named presets, never inline numbers. In Wingo UI,
springs.snappyandsprings.smootheach appear in more than 100 component files as of October 2026. About 15 component files still tune a spring inline for a specific gesture, and those are the exceptions worth reviewing, not the rule. Retuning the feel of the whole library is a one line change. - Presets on top of springs. A preset bundles
initial,animate,exitandtransition, so a popover is<motion.div {...presets.popover} />instead of four props that drift apart over time. - One reduced motion path.
useMotionTransition(springs.smooth)returns the spring, or{ duration: 0 }when the user asked for reduced motion, anduseMotionPreset("popover")turns movement into a short opacity fade. Both read the preference after hydration, so server and client markup match. Our prefers-reduced-motion guide explains why that matters in Next.js.
If you prefer a provider, motion's MotionConfig accepts a transition that becomes the default for every motion component inside it, so <MotionConfig transition={springs.smooth}> at the root replaces motion's built-in defaults for your app. Two caveats: that default also applies to opacity and colors, which then lose motion's 0.3 second tween, and reduced motion is a separate setting: reducedMotion="user" on the same MotionConfig switches transform animations off when the system asks for it. Components that need snappy still pass it explicitly.
To get the whole file, run npx wingo-ui@latest add motion. It is free, installs the motion package and the SSR-safe media query hook it uses for reduced motion.
Can CSS transitions use the same spring?
Yes, for the cases that do not go through motion, such as a Tailwind hover or a data-state change. CSS linear() takes a list of points and draws the curve through them, so you can sample a spring once and use it as an easing. MDN marks linear() as Baseline, available across browsers since December 2023.
Wingo UI ships two sampled twins as tokens in globals.css: --motion-ease-snappy with --motion-duration-snappy (450ms) for snappy, and --motion-ease-spring with --motion-duration-spring (500ms) for smooth. You can see the overshoot in the numbers: the snappy curve peaks at 1.0398, the 4% from the table above.
A sampled curve cannot keep velocity when it is interrupted, so use it for simple state changes and keep drags, thumbs and anything retargeted often on motion springs.
What mistakes make springs feel wrong?
- Animating with springs that were never named. Every inline
stiffnessis a future inconsistency. Search your codebase forstiffness:outside the presets file. - Bouncy on things people open all day. Keep the overshoot for moments that deserve it.
- Bouncy springs on opacity and colors. Opacity stops at 1, so a 20% overshoot is invisible and only delays the end of the animation. A fade on its own reads better as a short tween, which is also motion's default for non-transform values. When opacity rides along with a transform on smooth, as in the presets above, the 0.4% overshoot is too small to matter.
- Duration and physics in one object. Motion's docs state that
bounceanddurationare overridden whenstiffness,dampingormassare set, so{ duration: 0.2, stiffness: 400 }silently ignores the duration. - No reduced motion path. Movement that ignores the system setting can make people sick. Route every spring through one hook.
For more guides like this one, browse component guides, or start with the pillar, our guide to React form components, which uses these springs in every field.
What should you install next?
Start with the presets: npx wingo-ui@latest add motion copies lib/motion.ts into your project, free, with the four springs, the presets, the gesture thresholds and the reduced motion hooks. Add the free Button, Switch or Segmented Control next and they pick up the same springs automatically.
FAQ
What are good stiffness and damping values for a Framer Motion spring?
For UI, stiffness between 120 and 500 with a damping ratio between about 0.7 and 0.9 covers most needs; go lower only for a deliberate bounce. Our four presets are 500 / 32 for presses and toggles, 300 / 30 for overlays and layout, 400 / 18 for playful accents and 120 / 20 for large surfaces, all with the default mass of 1.
What spring does Framer Motion use by default?
In motion 12.43 a transform like x or y animates on stiffness 500 and damping 25, scale animates on stiffness 550 and damping 30 (critically damped when it heads to 0), and opacity or colors get a 0.3 second tween. If you pass type: "spring" without numbers, the physics defaults are stiffness 100, damping 10 and mass 1, which overshoots about 16%.
Should I use duration and bounce or stiffness and damping?
Use duration and bounce when a designer gives you a time, and stiffness and damping when you want the spring to keep the velocity of a gesture or an interrupted animation. Motion's docs say physics springs incorporate that velocity and duration based springs do not, and setting stiffness, damping or mass overrides duration and bounce.
How do I stop a Framer Motion spring from bouncing?
Raise damping until the damping ratio reaches 1, which means damping at least 2 * sqrt(stiffness * mass). For stiffness 300 and mass 1 that is about 35; anything above it settles without overshoot, just more slowly.
Is Framer Motion the same as the motion package?
Yes. Framer Motion is now published as motion, and the upgrade guide on motion.dev swaps npm install framer-motion for npm install motion and imports from motion/react. Spring options such as stiffness, damping and mass work the same way.
- Motion
- Animation
- React
- Design systems


