React Motion is an animation library for React applications that makes it easy to create and implement realistic animations. In this guide, we’ll demonstrate how to install the library and share some basic tips to help you build natural-looking, physics-based animations for your React projects.
Create a new React project by running:
npx create-react-app intro-react-motion
To install React Motion, run the following command inside your project root.
npm i react-motion
The react-motion
library exports the following.
spring
— A helper function that dictates how the component animatespresets
— An object of predefined animation propertiesMotion
— A component that is used to animate a componentStaggeredMotion
— A component that is used to animate components whose animation depends on each otherTransitionMotion
— A component that is used to animate the mount and unmounts of componentsFor the sake of brevity, this guide will focus on spring
, presets
, and Motion
.
spring()
and presets
The spring()
helper function defines how to animate from the initial style value to the destination value. It takes in two arguments: the value and an option animation config parameter.
For example, spring(10, { stiffness: 130, damping: 42 })
animates the value to 10 with a stiffness of 130 and damping of 42. stiffness
and damping
are animation properties that define the animation’s behavior. Don’t worry — it’s normal not to understand how these properties work.
The presets
properties are used as the animation configuration. For example, spring(25, presets.wobbly)
. Other preset values include presets.gentle
, presets.noWobble
, presets.stiff
.
<Motion />
componentThe <Motion />
component takes in two props: defaultStyle
and style
. The defaultStyle
prop defines the initial values of the style object. The style
prop is an object that defines the style values at any given point. The values of the style
prop are determined using the spring()
helper function. If the defaultStyle
is the original style, then style
is the final style that the components animate to.
The <Motion />
component expects a function as its child prop, which means it uses the render prop pattern. The function receives an interpolated style object, which contains the style value at any given time until the animation is completed.
<<Motion defaultStyle={{ scale: 0, translateX: -300 }} style={{ scale: spring(1), translateX: spring(0, presets.stiff) }} > {interpolatesStyles => <>{/* React Component */}</>} </Motion>
Let’s look at a basic example.
At the top of your component file, import Motion
, spring
, and presets
from the react-motion
library to use them in your component.
import { Motion, spring, presets } from "react-motion";
Create an <h1>
element in the component that will be animated inside App.js
.
// ... function App() { return ( <div className="App"> <div> <h1>Basic Animation Example</h1> </div> </div> ); } // ...
Now wrap your component with the <Motion />
component and return the <h1>
component from the render prop function. Pass { opacity: 0, translateY: 30 }
in the defaultStyle
prop. In the style
prop, use the spring()
helper function to interpolate the style values.
// ... <Motion defaultStyle={{ opacity: 0, translateY: 30 }} style={{ opacity: spring(1), translateY: spring(0, presets.wobbly) }} > {interpolatedStyles => ( <div style={{ transform: `translateY(${interpolatedStyles.translateY}px)`, opacity: interpolatedStyles.opacity }} > <h1>Basic Animation Example</h1> </div> )} </Motion> // ...
Here’s the final code:
import React from "react"; import "./styles.css"; import { Motion, spring, presets } from "react-motion"; function App() { return ( <div className="App"> <Motion defaultStyle={{ opacity: 0, translateY: 30 }} style={{ opacity: spring(1), translateY: spring(0, presets.wobbly) }} > {interpolatedStyles => ( <div style={{ transform: `translateY(${interpolatedStyles.translateY}px)`, opacity: interpolatedStyles.opacity }} > <h1>Basic Animation Example</h1> </div> )} </Motion> </div> ); } export default App;
Run the following command to see the above code in action.
npm start
The animation will start as soon as the component mounts on to the DOM. Now let’s see how you can also trigger the animation with a button click.
Using state, you can add style dynamically to interpolate the style values. In a variable, store the initial style for the animation.
function App() { const [startAnimation, setAnimation] = useState(false); const initialStyle = { opacity: 0, translateY: 30 }; // ... }
In the <Motion />
component, you don’t have to specify the defaultStyle
prop because the style
prop is going to change dynamically.
// ... <Motion style={ startAnimation ? { opacity: spring(1), translateY: spring(0, presets.wobbly) } : initialStyle } > {interpolatedStyles => ( <div style={{ transform: `translateY(${interpolatedStyles.translateY}px)`, opacity: interpolatedStyles.opacity }} > <h1>Triggered Animation</h1> </div> )} </Motion> // ...
Add two buttons: one to trigger the animation and another to reset the animation.
// ... <button onClick={() => setAnimation(true)}>Trigger Animation</button> <button onClick={() => setAnimation(false)}>Reset Animation</button> // ...
When the startAnimation
state is set to true
, the style
prop will get the initial style values. When it sets to false
, the style
prop will have the final values.
Your App.js
should look as follows.
import React, { useState } from "react"; import "./styles.css"; import { Motion, spring, presets } from "react-motion"; export default function App() { const [startAnimation, setAnimation] = useState(false); const initialStyle = { opacity: 0, translateY: 30 }; return ( <div className="App"> <Motion style={ startAnimation ? { opacity: spring(1), translateY: spring(0, presets.wobbly) } : initialStyle } > {interpolatedStyles => ( <div style={{ transform: `translateY(${interpolatedStyles.translateY}px)`, opacity: interpolatedStyles.opacity }} > <h1>Triggered Animation</h1> </div> )} </Motion> <button onClick={() => setAnimation(true)}>Trigger Animation</button> <button onClick={() => setAnimation(false)}>Reset Animation</button> </div> ); }
styled-components
You can use react-motion
with any other UI library for React. Let’s see how you can use react-motion
with the styled-components
library.
Install styled-components
by running the following command inside your project root.
npm i styled-components
Create the styled <Title />
component as follows.
// .. import styled from "styled-components"; const Title = styled.h1` color: #007bff; font-size: 32px; ${props => `transform: translateY(${props.translateY}px); opacity: ${props.opacity}; `} `; // ..
Similar to the above examples, return the <Title />
component from the render prop function. Pass the interpolated values as props to the <Title />
component.
<Motion style={ startAnimation ? { opacity: spring(1), translateY: spring(0, presets.wobbly) } : initialStyle } > {interpolatedStyles => ( <Title opacity={interpolatedStyles.opacity} translateY={interpolatedStyles.translateY} > Triggered Animation </Title> )} </Motion>
Your complete App.js
should look as follows.
import React, { useState } from "react"; import "./styles.css"; import { Motion, spring, presets } from "react-motion"; import styled from "styled-components"; const Title = styled.h1` color: #007bff; font-size: 32px; ${props => `transform: translateY(${props.translateY}px); opacity: ${props.opacity}; `} `; export default function App() { const [startAnimation, setAnimation] = useState(false); const initialStyle = { opacity: 0, translateY: 30 }; return ( <div className="App"> <Motion style={ startAnimation ? { opacity: spring(1), translateY: spring(0, presets.wobbly) } : initialStyle } > {interpolatedStyles => ( <Title opacity={interpolatedStyles.opacity} translateY={interpolatedStyles.translateY} > Triggered Animation </Title> )} </Motion> <button onClick={() => setAnimation(true)}>Trigger Animation</button> <button onClick={() => setAnimation(false)}>Reset Animation</button> </div> ); }
Regardless of which library you are using, react-motion
will work as long as the library supports custom styling.
If you encounter errors, depreciated warnings, or things that don’t run as expected, revert to the original versions of these libraries by replacing your dependencies inside package.json
file with the following versions.
//... "dependencies": { "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", "react": "^16.13.0", "react-dom": "^16.13.0", "react-motion": "^0.5.2", "react-scripts": "3.4.0", "styled-components": "^5.0.1" } //...
Then run:
npm i
This will install the exact same dependencies on which these examples were tested.
React Motion is one of the easiest animation libraries out there for animating components in React. This was just a brief introduction to the react-motion
library. As a next step, I would recommend looking into components such as <StaggeredMotion />
and <TransitionMotion />
, which are similar to the <Motion />
component but have an advanced implementation for more complex animations.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]