A spring that solves your animation problems.
—
React Motion's spring system provides physics-based animation configurations that feel more natural than traditional easing curves. Instead of specifying durations, you define spring characteristics like stiffness and damping to control animation behavior.
Creates a spring configuration object that defines how a value should animate to its target.
/**
* Creates spring configuration for animated values
* @param val - Target value for the animation
* @param config - Optional spring configuration parameters
* @returns OpaqueConfig object for internal use by Motion components
*/
function spring(val/*: number */, config/*?: SpringHelperConfig */)/*: OpaqueConfig */;Usage Examples:
import { spring } from 'react-motion';
// Basic spring with default settings
const basicSpring = spring(100);
// Custom spring configuration
const customSpring = spring(100, {
stiffness: 120,
damping: 17,
precision: 0.1
});
// Using in Motion component
<Motion
style={{
x: spring(targetX),
y: spring(targetY, {stiffness: 200, damping: 20}),
opacity: spring(1, {stiffness: 300, damping: 30})
}}
>
{({x, y, opacity}) => (
<div style={{
transform: `translate(${x}px, ${y}px)`,
opacity
}}>
Animated element
</div>
)}
</Motion>Configuration object for customizing spring behavior.
/**
* Configuration options for spring behavior
* All properties are optional and have sensible defaults
*/
/*::
type SpringHelperConfig = {
stiffness?: number, // Spring stiffness - higher values create snappier animations (default: 170)
damping?: number, // Spring damping - higher values reduce oscillation (default: 26)
precision?: number, // Animation precision threshold - smaller values run longer (default: 0.01)
};
*/Internal spring configuration object returned by the spring function. Not meant for direct manipulation.
/**
* Internal spring configuration object
* Used internally by Motion components - do not modify directly
*/
/*::
type OpaqueConfig = {
val: number, // Target value for animation
stiffness: number, // Spring stiffness parameter
damping: number, // Spring damping parameter
precision: number, // Precision threshold for stopping animation
};
*/Pre-defined spring configurations for common animation styles.
/**
* Pre-defined spring configuration presets
* Use these for common animation styles
*/
const presets = {
/** Default balanced preset - smooth with minimal bounce */
noWobble: { stiffness: 170, damping: 26 },
/** Gentle, slower animation with soft easing */
gentle: { stiffness: 120, damping: 14 },
/** More oscillation and bounce */
wobbly: { stiffness: 180, damping: 12 },
/** Quick, snappy animation with minimal overshoot */
stiff: { stiffness: 210, damping: 20 }
};Usage Examples:
import { spring, presets } from 'react-motion';
// Using presets
const gentleSpring = spring(100, presets.gentle);
const wobblySpring = spring(50, presets.wobbly);
const stiffSpring = spring(200, presets.stiff);
// Comparing presets in action
function PresetDemo() {
const [active, setActive] = useState(null);
const presetConfigs = [
{ name: 'noWobble', config: presets.noWobble },
{ name: 'gentle', config: presets.gentle },
{ name: 'wobbly', config: presets.wobbly },
{ name: 'stiff', config: presets.stiff }
];
return (
<div>
{presetConfigs.map(({ name, config }) => (
<Motion
key={name}
style={{
x: spring(active === name ? 200 : 0, config)
}}
>
{({ x }) => (
<div
style={{
transform: `translateX(${x}px)`,
padding: '10px',
margin: '5px 0',
background: '#007bff',
color: 'white',
cursor: 'pointer',
width: '200px'
}}
onClick={() => setActive(active === name ? null : name)}
>
{name}: stiffness={config.stiffness}, damping={config.damping}
</div>
)}
</Motion>
))}
</div>
);
}Utility function that extracts plain numeric values from style objects containing spring configurations.
/**
* Extracts plain numeric values from spring-configured style objects
* @param style - Style object that may contain spring configurations
* @returns PlainStyle object with numeric values only
*/
function stripStyle(style/*: Style */)/*: PlainStyle */;Usage Examples:
import { stripStyle, spring } from 'react-motion';
// Style with springs
const styleWithSprings = {
x: spring(100, { stiffness: 120 }),
y: spring(200),
opacity: 1, // plain number
scale: spring(1.5, { damping: 20 })
};
// Extract plain values
const plainStyle = stripStyle(styleWithSprings);
// Result: { x: 100, y: 200, opacity: 1, scale: 1.5 }
// Useful for getting initial values
function MyComponent() {
const targetStyle = {
width: spring(expanded ? 300 : 100),
height: spring(expanded ? 200 : 50)
};
return (
<Motion
defaultStyle={stripStyle(targetStyle)} // Initial values without animation
style={targetStyle}
>
{interpolatedStyle => (
<div style={interpolatedStyle}>
Content
</div>
)}
</Motion>
);
}Controls how quickly the spring tries to reach its target:
// Slow, gentle movement
spring(100, { stiffness: 80 })
// Quick, responsive movement
spring(100, { stiffness: 250 })Controls how much the spring oscillates around its target:
// Bouncy animation
spring(100, { damping: 10 })
// Smooth with no overshoot
spring(100, { damping: 40 })Controls when the animation stops:
// Very precise, runs until nearly perfect
spring(100, { precision: 0.001 })
// Less precise, stops when "close enough"
spring(100, { precision: 0.1 })// UI Elements (buttons, menus)
spring(value, { stiffness: 300, damping: 30 })
// Layout changes (expanding panels)
spring(value, { stiffness: 120, damping: 17 })
// Playful interactions (hover effects)
spring(value, { stiffness: 180, damping: 12 })
// Smooth, professional (form transitions)
spring(value, { stiffness: 170, damping: 26 })
// Snappy mobile interactions
spring(value, { stiffness: 400, damping: 28 })Modal/Dialog Animations:
// Entry
{ stiffness: 300, damping: 30 }
// Exit
{ stiffness: 400, damping: 40 }List Item Transitions:
{ stiffness: 200, damping: 22 }Drag and Drop:
// While dragging
{ stiffness: 400, damping: 40 }
// Snap back
{ stiffness: 300, damping: 30 }Loading Animations:
{ stiffness: 150, damping: 15 } // Bouncy for attentionfunction AdaptiveSpring({ urgent, value }) {
const config = urgent
? { stiffness: 400, damping: 28 } // Fast for urgent changes
: { stiffness: 120, damping: 20 }; // Gentle for normal changes
return (
<Motion style={{ x: spring(value, config) }}>
{({ x }) => <div style={{ transform: `translateX(${x}px)` }} />}
</Motion>
);
}function DynamicSpring() {
const [distance, setDistance] = useState(0);
// Adjust stiffness based on distance
const stiffness = Math.max(120, Math.min(300, distance * 2));
return (
<Motion
style={{
x: spring(distance, { stiffness, damping: 20 })
}}
>
{({ x }) => (
<div
style={{ transform: `translateX(${x}px)` }}
onClick={(e) => setDistance(e.clientX)}
>
Click to move (stiffness: {stiffness})
</div>
)}
</Motion>
);
}// Combining springs and static values
const mixedStyle = {
// Animated properties
x: spring(targetX, presets.stiff),
y: spring(targetY, presets.gentle),
scale: spring(targetScale),
// Static properties (no animation)
color: 'blue',
fontSize: 16,
fontWeight: 'bold'
};Unlike CSS transitions, spring animations don't have fixed durations:
Install with Tessl CLI
npx tessl i tessl/npm-react-motion