Table of Contents
- What is React Spring?
- Installation
- Core Concepts
- Advanced Hooks
- Practical Examples
- Performance Considerations
- React Spring vs. Other Animation Libraries
- Conclusion
- References
What is React Spring?
React Spring is a physics-based animation library for React that models animations after real-world spring behavior. Instead of defining fixed durations or keyframes (as in CSS), you define “spring” parameters like tension (stiffness) and friction (damping), and the library calculates the motion dynamically. This results in animations that feel natural—easing in/out smoothly, overshooting slightly, and settling organically—mimicking how objects move in the physical world.
Key Features:
- Physics-based motion: Animations respond to user input (e.g., drag, hover) in real time.
- Declarative API: Define animations with hooks, making it easy to integrate with React state.
- Lightweight: ~10KB gzipped (smaller than alternatives like Framer Motion).
- Flexible: Animate any value (numbers, colors, transforms, etc.) and interpolate between states.
- Broad compatibility: Works with React, React Native, and even vanilla JS.
Installation
Getting started with React Spring is straightforward. Install it via npm or yarn:
# Using npm
npm install react-spring
# Using yarn
yarn add react-spring
For advanced features like drag-and-drop or gesture support, install additional add-ons:
npm install react-spring/addons # For useDrag, useScroll, etc.
Core Concepts
To harness React Spring’s power, let’s break down its fundamental building blocks.
The useSpring Hook
The useSpring hook is the workhorse of React Spring. It defines an animation by mapping a target state to an animated value, using spring physics to interpolate between the current and target states.
Basic Syntax:
import { useSpring, animated } from 'react-spring';
function MyComponent() {
// Define spring configuration and target values
const props = useSpring({
from: { opacity: 0, scale: 0.5 }, // Initial state
to: { opacity: 1, scale: 1 }, // Target state
config: { tension: 200, friction: 10 } // Spring parameters
});
return <animated.div style={props}>Hello, React Spring!</animated.div>;
}
from: The initial state of the animation (e.g.,opacity: 0for a fade-in).to: The target state (e.g.,opacity: 1to fade in).config: Optional spring parameters:tension: Stiffness of the spring (higher = tighter, more abrupt motion).friction: Damping (higher = slower, less bounce).mass: Weight of the object (higher = slower acceleration).duration: Override physics with a fixed time (ms) for time-based animations.
The animated Component
React Spring animations require the animated HOC (higher-order component) to apply animated values to DOM elements. Wrap any element (e.g., div, span, img) with animated to make it animatable:
<animated.div style={props}>Animated Content</animated.div>
animated works with all standard HTML elements and most React components (e.g., from Material-UI or Chakra UI).
Interpolations
React Spring animates raw values (numbers, colors, etc.), but you’ll often need to map these values to CSS properties. This is where interpolations come in. Use the interpolate method to transform animated values into usable styles.
Example: Animate Color and Scale
const props = useSpring({
from: { value: 0 },
to: { value: 1 },
config: { duration: 1000 }
});
// Interpolate: value 0 → 1 maps to:
// - scale: 0.5 → 1
// - color: red → blue
const interpolated = props.value.interpolate({
range: [0, 1],
output: [
{ scale: 0.5, color: 'red' },
{ scale: 1, color: 'blue' }
]
});
return <animated.div style={interpolated}>Animate Me!</animated.div>;
You can also interpolate inline with template literals:
const style = {
transform: props.value.interpolate(v => `scale(${v})`),
color: props.value.interpolate(v => `hsl(${v * 360}, 100%, 50%)`)
};
Advanced Hooks
Beyond useSpring, React Spring offers hooks for complex animations involving multiple elements or dynamic state changes.
useSprings: Multiple Independent Animations
Use useSprings to animate a list of elements with independent spring configurations. Ideal for grids or galleries where each item needs its own animation.
Example: Animate a List of Items
import { useSprings } from 'react-spring';
function SpringList() {
const items = ['Item 1', 'Item 2', 'Item 3'];
// Create a spring for each item
const springs = useSprings(items.length, items.map((item, index) => ({
from: { opacity: 0, y: -20 },
to: { opacity: 1, y: 0 },
delay: index * 100, // Stagger animations by 100ms
config: { tension: 150, friction: 10 }
})));
return (
<div>
{springs.map((props, index) => (
<animated.div key={index} style={{ ...props, margin: '10px' }}>
{items[index]}
</animated.div>
))}
</div>
);
}
useTrail: Sequential Animations
useTrail creates a follow-the-leader effect, where each element in a list animates after the previous one. Perfect for menus or cascading lists.
Example: Trail Animation
import { useTrail, animated } from 'react-spring';
function TrailMenu() {
const [open, setOpen] = useState(false);
const items = ['Home', 'About', 'Contact'];
// Trail animations: each item follows the first
const trail = useTrail(items.length, {
from: { opacity: 0, x: -20 },
to: { opacity: open ? 1 : 0, x: open ? 0 : -20 },
config: { tension: 200, friction: 10 }
});
return (
<div>
<button onClick={() => setOpen(!open)}>Toggle Menu</button>
<div>
{trail.map((props, index) => (
<animated.div key={index} style={props}>
{items[index]}
</animated.div>
))}
</div>
</div>
);
}
useTransition: Mount/Unmount Animations
useTransition handles animations for elements being mounted or unmounted (e.g., modals, slideshows, or dynamic lists). It tracks the “presence” of elements and animates their entry/exit.
Example: Slideshow with Transitions
import { useTransition, animated } from 'react-spring';
function Slideshow() {
const [index, setIndex] = useState(0);
const slides = ['Slide 1', 'Slide 2', 'Slide 3'];
// Transition for the active slide
const transitions = useTransition(slides[index], {
from: { opacity: 0, transform: 'translate3d(100%, 0, 0)' },
enter: { opacity: 1, transform: 'translate3d(0%, 0, 0)' },
leave: { opacity: 0, transform: 'translate3d(-50%, 0, 0)' },
config: { tension: 300, friction: 20 }
});
return (
<div>
<button onClick={() => setIndex((prev) => (prev + 1) % slides.length)}>
Next Slide
</button>
<div style={{ height: '200px' }}>
{transitions((props, item) => (
<animated.div style={props}>{item}</animated.div>
))}
</div>
</div>
);
}
Practical Examples
Let’s put these concepts into action with real-world scenarios.
Example 1: Hover Animation
Add a smooth scale effect to a button on hover using useSpring and React state.
import { useSpring, animated } from 'react-spring';
function AnimatedButton() {
const [hovered, setHovered] = useState(false);
// Animate scale based on hover state
const props = useSpring({
scale: hovered ? 1.1 : 1,
config: { tension: 300, friction: 10 }
});
return (
<animated.button
style={{
padding: '1rem 2rem',
fontSize: '1.2rem',
cursor: 'pointer',
transform: props.scale.interpolate(s => `scale(${s})`),
transition: 'transform 0.2s' // Fallback for non-animated states
}}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
Hover Me!
</animated.button>
);
}
Example 2: List Transitions
Animate items being added to/removed from a list using useTransition.
import { useTransition, animated } from 'react-spring';
import { useState } from 'react';
function AnimatedList() {
const [items, setItems] = useState(['Item 1']);
// Add item on button click
const addItem = () => {
setItems([...items, `Item ${items.length + 1}`]);
};
// Transition for new items
const transitions = useTransition(items, {
key: (item) => item,
from: { opacity: 0, height: 0, margin: 0 },
enter: { opacity: 1, height: 60, margin: 8 },
leave: { opacity: 0, height: 0, margin: 0 },
config: { tension: 200, friction: 10 }
});
return (
<div>
<button onClick={addItem}>Add Item</button>
<div>
{transitions((props, item) => (
<animated.div style={{ ...props, border: '1px solid #ddd', padding: 16 }}>
{item}
</animated.div>
))}
</div>
</div>
);
}
Example 3: Drag-and-Drop Interaction
Add drag-and-drop with smooth animations using useDrag from react-spring/addons.
import { useSpring, animated } from 'react-spring';
import { useDrag } from 'react-spring/addons';
function DraggableBox() {
// Track position with spring
const [props, setProps] = useSpring(() => ({
x: 0,
y: 0,
config: { mass: 1, tension: 300, friction: 20 }
}));
// Use drag hook to track mouse/touch position
const bind = useDrag(({ down, movement: [mx, my] }) => {
setProps({
x: down ? mx : 0, // Snap back when released
y: down ? my : 0,
immediate: down // Disable animation while dragging
});
});
return (
<animated.div
{...bind()} // Attach drag handlers
style={{
width: '100px',
height: '100px',
background: 'blue',
cursor: 'grab',
transform: props.x.interpolate((x, y) => `translate3d(${x}px, ${y}px, 0)`)
}}
/>
);
}
Performance Considerations
React Spring is optimized for performance, but follow these tips to ensure smooth animations:
- Animate transform and opacity: These properties are handled by the GPU and avoid layout recalculations (reflows). Avoid animating
width,height, ormarginunless necessary. - Use
memofor static components: Wrap components withReact.memoto prevent unnecessary re-renders. - Limit spring count: Too many concurrent springs can strain the main thread. Use
useSpringsfor lists instead of individualuseSpringhooks. - Native driver (React Native): For React Native, use
react-spring/nativeto offload animations to the native thread.
React Spring vs. Other Animation Libraries
| Library | Use Case | Pros | Cons |
|---|---|---|---|
| React Spring | Physics-based, dynamic animations | Lightweight, natural motion, flexible | Steeper learning curve for advanced hooks |
| Framer Motion | High-fidelity, production-ready animations | Rich API, built-in gestures, components | Larger bundle size (~30KB gzipped) |
| React Transition Group | Simple enter/exit transitions | Minimal, easy to learn | No physics; relies on CSS classes |
Conclusion
React Spring empowers developers to create fluid, natural animations in React with minimal effort. Its physics-based approach ensures animations feel lifelike, while its hook-based API integrates seamlessly with React state and components. Whether you’re building a simple hover effect or a complex interactive UI, React Spring provides the tools to make your app feel polished and engaging.
Ready to animate? Dive into the official docs and start experimenting—your users will thank you!