This website uses cookies to ensure you get the best experience on our website. Learn More.

React Spring Tutorial: Making Animated React Apps In 2022

React Spring Tutorials - Slinky by Jackie Elliott

Incorporating animation to UI design can be a tricky thing. In 2020, we published an article describing “butter-smooth” animations in a React app made with Framer Motion v1.6.17. 

Studying the React Spring library can make people face the opposite problem. Although its documentation is well-ordered, detailed, easy to use, and has a lot of impressive examples, most of them are too complicated if your aim is to get the basics. So we thought that making some React Spring tutorials could be helpful.

This article will be useful to those starting out with React Spring. We’ll be looking over various methods for combining multiple springs for more complicated React animations, examples included. Note that a basic knowledge of React is required to understand this article. Knowing how to use styled-components / emotion / any other similar library would also be helpful.

5 hooks of the React Spring library 

Animations add life to design and improve the UX of an app. 

React Spring is a physics-based animation library. It calculates all the mechanics behind the scenes for nice and smooth animation and allows to configure it for a user both partially and completely. What’s more, React Spring makes it easier than using pure CSS (at least, without an insanely complicated and hard-to-maintain bulk of code). 

At the moment, the React Spring library contains 5 hooks:

  1. useSpring – a single animation that changes the state of the animation a => b.
  2. useSprings – multiple spring animations for lists that also change the animation state a => b.
  3. useTrail – multiple spring animations with a common data set, where each subsequent animation trails behind the previous one.
  4. useTransition – animations on mount/unmount for lists, where the elements get added, deleted and updated.
  5. useChain – used to determine the order and sequence of execution of several previously defined animations.

All these 5 hooks of the React Spring library are similar in nature, but each of them has its own peculiarity. Let’s examine every one of them individually in more detail to learn how to apply them for making beautiful animations in React.

useSpring

We’ll start this React Spring animation tutorial with the simplest hook – useSpring. It transforms the passed values into animated ones.

For the first example, we’ll create a simple animation component, that will resize and shift the backgroundPosition on click. 

First, let’s import the required hook and animated component:

import { animated, useSpring } from “react-spring”;

For animation on appearance it will be enough to indicate the following:

const springProps = useSpring({
   from: { opacity: 0, ... },
   to: { opacity: 1, ... }
 })

Spring allows animating the state changes from the initial from to the final to. 

Besides, the to prop can be omitted to make it more simple:

const springProps = useSpring({
   opacity: 1,
   from: { opacity: 0 },
 })

You can animate almost any CSS property or use arbitrary names, excluding the reserved keywords.

Next, you’ll need to pass springProps to the animated element. It’s worth mentioning though, that since the transmitted values are getting updated, they cannot be used with ordinary components or tags.

The following styled-components / emotion / etc component is required:

const AnimatedBox = styled(animated(ComponentName/TagName))`...`;

Or just any HTML tag, with the addition of the “animated” prefix: 

<animated.button>Button</animated.button>

Animated is an animation-primitive that allows you to handle the passed animated props. Animated extends the capabilities of native elements so that they can accept animated values.

What’s left is to pass the prop to the required component:

<AnimatedBox style={{springProps}} />

React Spring hooks can take almost any value or color, HTML attribute, and even a string pattern (for example, borderTop: “6px solid red”), etc. One very unfortunate limitation is that it’s impossible to transfer different properties for from and to in a single prop. That is, px must be converted to px, % => %, number => number, etc., or an error will occur.

As you can see from the example below, animation states can be destructured if the need arises. This is useful if, for example, you need to describe the animation states for several components at once, when using arbitrary names.

We’ll use useState to change the animation states. Since we pass both true and false values for animated props with the ternary operator, we don’t necessarily have to define initial from values for this particular case, but it’s better to be safe than sorry and define it anyway for error-proof. Otherwise, the prop data will be empty before making changes to the state, and animation might break or cause an unexpected result.

const [clicked, setClicked] = useState(false);
 
 const { size, ..., ...springProps } = useSpring({
   size: clicked ? 300 : 200,
   backgroundPosition: clicked ? "50% 100%" : "50% 0%",
   ...
   from: {
     size: 200,
     backgroundPosition: "50% 0%"
     ...
   }
 });

We’ll destructure the value of size (it will be needed for animating both width and height) and pass the other values, in this case, the backgroundPosition, to springProps.

It remains only to pass the animated values to our component, and, of course, change its state on click:

<AnimatedItem
  style={{ height: size, width: size, ...springProps }}
  onClick={() => setClicked(!clicked)}
/>

Now, after being clicked, the state will change from false to true, so the height and width of the component will change from 200px to 300px, and the backgroundPosition of the background element will also change from “50% 0%” to “50% 100%”.

Perhaps it’s worth mentioning the counter for the ProgressBar used in this example. Let’s complete our hook with the following line of code:

counter: clicked ? 100 : 0,

It’s important not to forget to destructure the counter, as we’ll need it outside of the springProps passed to the AnimatedItem component.

To iterate over counter values from 0 to 100, we’ll use some interpolation:

<AnimatedBox>

  {counter.to(val => Math.floor(val) + "%")}

</AnimatedBox>

To put it another way, the interpolation allows you to iterate over values of a function or of a specified range of values. Note that the interpolation transferred to the animated primitive works more efficiently and takes up less space.

Quite simple, right?

useSprings

import { animated, useSprings } from “react-spring”;

The useSprings hook is slightly different from the previous hook. It creates multiple spring animations for static lists.

In this React Spring example, the colorful boxes are our list, which uses useSprings. useSprings takes the length of our list and determines the animation parameters for each of the list elements:

 const [springs, api] = useSprings(list.length, (index) => ({
   ...
 }));

useSprings in this example:

 const [springs, api] = useSprings(colorScheme.length, (index) => ({
   ...colorScheme[index],
   opacity: 1,
   borderRadius: "10%",
 }));

The background and color values are taken from the array of colorScheme object:

const colorScheme = [
  
  { name: "Red munsell", background: "#ec0b43",color: "#fff" }  ...
];

We will update the animation with a help of useCallback:

const handleOnClick = useCallback(() => {
  setIsHidden(!isHidden);
  api.start((index) => isHidden ? {
    opacity: 0.2, ...} : { opacity: 1, ...}
  );
}, [api, isHidden]);
<Box as="button" onClick={handleOnClick}>Click</Box>

We still got to pass the value of springs to the list of components:

<>
  {springs.map((props, i) => (
    <AnimatedItem style={props}>{props.name}</AnimatedItem>
  ))}
</>

Clicking the button will animate not one, but all the elements of useSprings.

useTrail

import { animated, useTrail, to } from “react-spring”;

useTrail allows you to create multiple spring animations with a single config, and each subsequent spring is executed after the previous one. It is used for staggered animation.

const [trail, api] = useTrail(list.length, { ... });

For this example the config looks approximately like this:

const [trail, set] = useTrail(imgList.length, () => ({
  opacity: 1, ...
  from: {
    opacity: 0, ...
  }
}));

Passing the trail into the component:

<GridContainer>
  {trail.map(({ sc, x, y, skewX, ...prop }, i) => (
    <AnimatedItem
      key={i}
      style={{
        ...prop,
        transform: to(
          [sc, x, y, skewX],
          (sc, x, y, skewX) =>
          `scale(${sc}) translate(${x}, ${y}) skewX(${skewX}deg)`
        )
      }}
      backgroundImage={`url(${imgList[i]}`}
    />
  ))}
</GridContainer>

What you should pay attention to in this example is the interpolation for a set of values, which allows you to change the transform property for several transform-functions at once. It differs slightly from the single parameter interpolation:

transform: x.to(x => `translateX(${x}px)`)

But the principle is the same. As a result, we got a trail animation that changes the values of transform property (scale, translate and skewX) and opacity on appearance, and also changes the scale once again when the list container is clicked. By clicking the button, the opacity will also be changed with the help of the already familiar to us set function.

useTransition

import { animated, useTransition, useSpringRef } from “react-spring”;

useTransition allows you to create an animated transition group. It takes in the elements of the list, their keys, and lifecycles. The animation is triggered on the appearance and disappearance of the elements. 

You can use transition for arrays, to toggle between components, or for mounting/unmounting of the same component.

Let’s create a slider with the help of useTransition:

 const [[index, dir], setIndex] = useState([0, 0]);
 const transRef = useSpringRef();
 
 const transitions = useTransition(index, {
   ref: transRef,
   keys: index,
   from: {
     transform: `translate3d(${dir === 1 ? 100 : -100}%,0,0) scale(0.8)`
   },
   enter: { ... },
   leave: { ... },
 });
 
 useEffect(() => {
   transRef.start();
 }, [index]);

useSpringRef() is library’s version of useRef hook. It’s used to get access to api methods to control the animations.

The from, enter, leave properties describe the state of the current slide from from to enter on mount and from enter to leave on unmount.

Let’s pass our config to the component:

{transitions((styles, i) => (
  <Slide style={styles} background={`url(${slides[i].url}`} />
))}

The value of index and the direction of slides (dir) change on clicking the arrow controls:

<Arrow onClick={() => handleNextSlide(-1)} />
<Arrow onClick={() => handleNextSlide(1)} />

Where handleNextSlide is callback that takes direction (-1 for previous slide and 1 for next slide).

handleNextSlide allows not only changing the value of index and dir, but also resetting it after reaching the last slide.

As a result, we got a slider where the slides get mounted/unmounted, changing the values of opacity and transform when index and dir get changed. 

Control bullets are animated using the already familiar useSrings hook, so we won’t dwell on them.

useChain

useChain allows you to set the execution sequence of previously defined animation hooks. To do this, you need to use refs, which will subsequently prevent the independent execution of the animation.

import { animated, useChain, useSpringRef } from “react-spring”;

Let’s use this hook to animate the hamburger menu element. In our case, first, the useSpring animation of the MenuBar will execute, followed by useSprings animation for the list of Menu components – MenuItem.

Defining the ref for the useSpring and using the same principle, for the useSprings:

 const { ... , ...springProps } = useSpring({
   ref: springRef,
   ...
 });

All we have to do now is to define the order of execution of animations with useChain:

useChain(
   open ? [springRef, springsRef] : [springsRef, springRef],
   open ? [0, 0.25] : [0, 0.75]
 );

In this example, if the state is open === true, then on expanding the menu the animation for the MenuBar will execute first, followed by MenuItems. If open === false, that is, on closing the menu, the execution order is reversed.

After setting the order of animations, you can also specify timeSteps – an array of values between 0-1 (1 = 1000ms) that defines the beginning and end of the animations. For example, [0, 0.25] 0 * 1000ms = 0 and 0.25 * 1000ms = 250ms.

Bonus

A few bonus examples for this tutorial using the already familiar React Spring hooks:

Cards list – useSprings

Image gallery – useChain

useSpring + loop

Property use cases:

  • loop: true – repeat animation
  • Pass a function (loop: () => 3> n ++) which will be called after each loop iteration (return true to continue looping, false to stop)
  • Define a loop object (loop: {reverse: true}) for a separate customization of the loop animation. It may contain any useSpring properties, but the most interesting one is reverse: true, which prevents twitching when the loop is repeated.
import { animated, useSpring } from "react-spring";

Let’s configure the already familiar useSpring using the brand-new and shiny ✨ loop property:

const springProps = useSpring({
   loop: { reverse: true },
   from: { y: 0, rotate: 0 },
   to: { y: 100, rotate: 180 },
   config: { duration: 2500 }
 });

All that remains is to pass the config to our animated component:

<AnimatedItem style={springProps} />

That’s it! We got ourselves a seamless and easy way to configure loop animation. Can you imagine now that we couldn’t do it properly before?

Points to take away

Advantages of the React Spring library:

  • Animations are based on physics. There is no need (unless you intentionally want to) to customize duration or easing. The result is smooth, soft, and natural-looking animations.
  • Easy-to-use and clear documentation.
  • A lot of interesting and beautiful demos in the documentation + on the React Spring creator Paul Henschel’s CodeSandbox page.
  • If necessary, you can utilize a very useful set of hooks from use-gesture.
  • The library repository is continually being updated and maintained.
  • A small, but quite active community (spectrum, discord) has formed around the library.
  • Paul Henschel regularly shares interesting insights, demos, and more on his Twitter page.

Disadvantages of the React Spring library:

  • As we’ve already mentioned, another very unfortunate limitation of React Spring is that it’s impossible to transfer different properties for from and to in a single prop. That is, px must be converted to px, % => %, number => number, etc., or an error will occur.
  • Also, the library doesn’t allow you to animate the value of auto. The documentation suggests using react-resize-aware, react-measure, etc. for these, and other purposes that require the exact height and width of a component.

React Spring Alternatives:

Framer/motion 

A production-ready motion library for React. Utilize the power behind Framer, the best prototyping tool for teams. Proudly open source. 

  • Uses a simple animation and gesture API like the Framer library, while preserving the semantics of HTML and SVG. 
  • Makes it easy to port high-precision prototypes to a production-ready environment or create something completely new. 
  • Makes it easier for developers to understand how the prototype should function.

Framer/motion is also quite popular! It has 13.3k stars on GitHub, and almost half a million weekly downloads

The writing of the code in Framer is an interesting and exciting process that does not require any special preparation; moreover, the program’s website has very detailed documentation with examples and tutorials.

React Transition Group

React Transition Group is not an animation library, it does not animate styles by itself. Instead, it exposes transition stages, manages classes and group elements and manipulates the DOM in useful ways, making the implementation of actual visual transitions much easier. The React Transition Group component was developed by the ReactJS community team. It allows you to implement basic CSS animations and transitions worry-free.

It needs to be installed in the package for your React app, which will slightly increase the overall build size. 

React Transition Group has 8.9k stars on GitHub, and almost 4 million weekly downloads

React GSAP

This library lets you use the GreenSock Animation Platform (GSAP) in React in a fully declarative way. It abstracts away the direct use of the GSAP Tween and Timeline functions. If you’d like to learn about GSAP tutorials for beginners, pick into our standalone article on the topic

React GSAP has over 300 stars on GitHub and 5.5k weekly downloads

Written by Julia Shikanova and Kate Shokurova

* * *

This React Spring tutorial was originally published in March 2019 and was updated in January 2022 to make it more relevant and comprehensive.

*  *  *

Written by Julia Shikanova

January 01, 2022

Subscribe to Our Blog

Once a month we will send you blog updates