In this article we’ll be exploring one of the best animation frameworks for React: React Spring. You’ll learn some of the basics behind changing you component styling into smooth, physics-based transitions.
React Spring has both a hooks-based and a component-based API, we’ll be exclusively looking at using hooks with basic state for all our animations. So if you need some brushing up on React Hooks, I recommend this article.
Of course, we’re going to need react-spring, and we can just use Create React App to get started.
$ npx create-react-app react-spring-example
$ cd react-spring-example
$ npm i react-spring
In our App.js
file we’re going to need useSpring
and animated
from react-spring.
useSpring
is a custom hook that we can set our style to, it takes an object with the from
and to
values as the start and end states while react-spring handles the transition between them. from
and to
can take objects of almost every css property: color, size, transform, and even our scrollbar. To apply our spring animation, we just need to add animated
onto our HTML tags and pass our animation to our style. By default this is run as soon as the component is mounted.
Going from one value to another is maybe a little boring, but react-spring lets us use arrays to render animations with multiple stages. Just remember to always include the starting state with any property you want to add.
import React, { useState } from 'react';
import { useSpring, animated } from 'react-spring';
const App = () => {
const animation = useSpring({
from: { opacity: 0 },
to: { opacity: 1 }
});
const colorAnimation = useSpring({
from: { color: 'blue' },
to: { color: `rgb(255,0,0)` }
});
const multiAnimation = useSpring({
from: { opacity: 0, color: 'red' },
to: [
{ opacity: 1, color: '#ffaaee' },
{ opacity: 1, color: 'red' },
{ opacity: .5, color: '#008000' },
{ opacity: .8, color: 'black' }
]
});
return (
<div>
<animated.h1 style={animation}>Hello World</animated.h1>
<animated.h1 style={colorAnimation}>Hello World</animated.h1>
<animated.h1 style={multiAnimation}>Hello World</animated.h1>
</div>
)
};
export default App;
Adding some local state will allow us to add some actual interactions to our animations, instead of transitioning on mount. Instead of from
and to
we can use a ternary operator for our single step animations.
import React, { useState } from 'react';
const App = () => {
const [on, toggle] = useState(false);
const animation = useSpring({
color: on ? 'blue' : 'red'
});
return (
<div>
<animated.h1 style={animation}>{!on ? "I'm red" : "Now I'm blue" }</animated.h1>
<button onClick={() => toggle(!on)}>Change</button>
</div>
)
};
Besides only adding static style changes to our elements and components we can create more interesting and reusable animations using the interpolate
method. We can add variables to our spring, since it is also an object, and use interpolate
to extract them for our styles.
We just need to extract our value from our spring and use interpolate
to destructure it some more, throw them into some template literals and we’re good to go. This will allow us the freedom to set more dynamic values, like a color value that is based on the x position.
const App = () => {
const [on, toggle] = useState(false);
const { xy } = useSpring({
from: { xy: [0, 0], c: 'green' },
xy: on ? [800, 200] : [0, 0],
c: on ? 'red' : 'green'
});
return (
<div>
<animated.h1
style={{
transform: xy.interpolate((x, y) => `translate(${x}px, ${y}px)`),
color: c.interpolate(c => c)}}>
{!on ? "I'm here" : "Now I'm over here"}</animated.h1>
<button onClick={() => toggle(!on)}>Change</button>
</div>
)
};
One of the more useful aspects of interpolate
is that we can emulate CSS keyframes. Instead of passing a value into our spring, we’ll just set it to 1 or 0. Before we can interpolate it like before, we need to pass in an object with a range
and an output
. Range can be any value between 0 and 1 and works like setting breakpoints with CSS keyframes, the corresponding output is the value that will be prerendered.
A second interpolate
will then reset our style at every change in output.
const App = () => {
const [on, toggle] = useState(false)
const { x, c } = useSpring({
from: { xy: [0, 0], c: 0 },
x: on ? 1 : 0,
c: on ? 1 : 0
})
return (
<div>
<animated.h1
style={{
transform: x.interpolate({
range: [0, .25, .5, .75, 1],
output: [0, 500, 200, 800, 500]
}).interpolate(x => `translateX(${x}px)`),
color: c.interpolate({
range: [0, .5, 1],
output: ['red', 'blue', 'green']
}).interpolate(c => c)
}}>
{!on ? "I'm here" : "Now don't know where I'm going"}</animated.h1>
<button onClick={() => toggle(!on)}>Change</button>
</div>
)
}
On its own, the previous example is very abrupt and jarring. This is because of react-spring’s default configuration. The animations are mostly based off of a few properties that we are allowed to easily manipulate in our spring. The docs have a wonderful interactive example that really helps to get an intuitive feel for the different properties.
mass
: Affects the speed and how far it overshoots the transition.tension
: Affects the overall velocity.friction
: Controls the resistance and how quickly it decelerates.clamp
: Whether it should ever overshoot the transitions.const animation = useSpring({
{/* ... */}
config: {
mass: 5,
tension: 50,
friction: 25,
clamp: true
}
});
To help us out the team at react-spring even included some configuration presets we can import that will be very useful.
config.default
{ mass: 1, tension: 170, friction: 26 }config.gentle
{ mass: 1, tension: 120, friction: 14 }config.wobbly
{ mass: 1, tension: 180, friction: 12 }config.stiff
{ mass: 1, tension: 210, friction: 20 }config.slow
{ mass: 1, tension: 280, friction: 60 }config.molasses
{ mass: 1, tension: 280, friction: 120 }import { useSpring, animated, config } from 'react-spring';
const animation = useSpring({
{/* ... */}
config: config.wobbly
});
// Or you can just destructure it if you want to change other options
const animation = useSpring({
{/* ... */}
config: {
...config.molasses,
clamp: true
}
});
While the examples here may not have been the most flashy, I hope that they are enough to help you understand the basics behind React animations using react-spring. ✨
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Sign up for Infrastructure as a Newsletter.
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Great article, but shouldn’t we also destructure
c
in §Interpolate, like this:?
Thanks a lot, I have a question about interpolate in this article? How to use the extrapolateLeft、extrapolateRight、extrapolate、map parameters in the description?
https://www.react-spring.io/docs/hooks/api value.interpolate either takes an object of the following shape:
Value default Description extrapolateLeft extend Left extrapolate. Can be: identity/clamp/extend extrapolateRight extend Right extrapolate. Can be: identity/clamp/extend extrapolate extend Shortcut to set left and right-extrapolate range [0,1] Array of input ranges output undefined Array of mapped output ranges map undefined Value filter applied to input value