Top Related Projects
Declarative Animations Library for React and React Native
Open source, production-ready animation and gesture library for React
✌️ A spring physics based React animation library
🎊 A collection of animations for inline style libraries
Quick Overview
React-Motion is a spring animation library for React applications. It provides a way to create smooth, physics-based animations in React components, offering a more natural feel compared to traditional CSS transitions or animations.
Pros
- Provides natural-feeling animations based on spring physics
- Integrates seamlessly with React components
- Allows for fine-tuned control over animation parameters
- Supports both simple and complex animations
Cons
- Learning curve for developers unfamiliar with spring physics concepts
- Can be overkill for simple animations that could be achieved with CSS
- Performance may suffer with a large number of animated elements
- Limited built-in animation types compared to some other animation libraries
Code Examples
- Basic spring animation:
import { Motion, spring } from 'react-motion';
<Motion defaultStyle={{x: 0}} style={{x: spring(100)}}>
{({x}) => <div style={{transform: `translateX(${x}px)`}}>Hello</div>}
</Motion>
- Chained animations:
import { Motion, spring } from 'react-motion';
<Motion
defaultStyle={{x: 0, y: 0}}
style={{
x: spring(100, {stiffness: 120, damping: 17}),
y: spring(50, {stiffness: 120, damping: 17})
}}
>
{({x, y}) => (
<div style={{transform: `translate(${x}px, ${y}px)`}}>
Chained Animation
</div>
)}
</Motion>
- Staggered list animation:
import { StaggeredMotion, spring } from 'react-motion';
<StaggeredMotion
defaultStyles={[{h: 0}, {h: 0}, {h: 0}]}
styles={prevInterpolatedStyles => prevInterpolatedStyles.map((_, i) => {
return i === 0
? {h: spring(100)}
: {h: spring(prevInterpolatedStyles[i - 1].h)}
})}
>
{interpolatingStyles =>
<ul>
{interpolatingStyles.map((style, i) =>
<li key={i} style={{height: style.h}}>Item {i + 1}</li>
)}
</ul>
}
</StaggeredMotion>
Getting Started
-
Install react-motion:
npm install react-motion
-
Import the necessary components:
import { Motion, spring } from 'react-motion';
-
Use the Motion component in your React application:
function App() { return ( <Motion defaultStyle={{x: 0}} style={{x: spring(100)}}> {({x}) => <div style={{transform: `translateX(${x}px)`}}>Animated Div</div>} </Motion> ); }
Competitor Comparisons
Declarative Animations Library for React and React Native
Pros of Animated
- More flexible and can be used with non-React projects
- Supports a wider range of animation types, including spring animations and decay
- Better performance for complex animations due to its native driver option
Cons of Animated
- Steeper learning curve compared to React Motion
- Less intuitive API for React developers
- Requires more setup and configuration for basic animations
Code Comparison
React Motion:
import { Motion, spring } from 'react-motion';
<Motion defaultStyle={{x: 0}} style={{x: spring(100)}}>
{({x}) => <div style={{transform: `translateX(${x}px)`}} />}
</Motion>
Animated:
import { Animated } from 'react-native';
const animatedValue = new Animated.Value(0);
Animated.spring(animatedValue, { toValue: 100 }).start();
<Animated.View style={{transform: [{translateX: animatedValue}]}} />
Summary
React Motion is more React-centric and easier to use for simple animations, while Animated offers more flexibility and performance for complex animations across different platforms. React Motion's API is more declarative and intuitive for React developers, but Animated provides more control and a wider range of animation types. The choice between the two depends on the specific project requirements, target platforms, and the developer's familiarity with each library.
Open source, production-ready animation and gesture library for React
Pros of Motion
- More comprehensive animation API with a wider range of features
- Better TypeScript support and type definitions
- Easier to use for complex animations and gestures
Cons of Motion
- Larger bundle size due to more features
- Steeper learning curve for beginners
- May be overkill for simple animations
Code Comparison
React Motion:
<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
{({x}) => <div style={{transform: `translateX(${x}px)`}} />}
</Motion>
Motion:
<motion.div
initial={{x: 0}}
animate={{x: 10}}
transition={{type: "spring"}}
/>
Key Differences
- Motion offers a more declarative API, while React Motion uses a more functional approach
- Motion provides built-in components (e.g.,
motion.div
), whereas React Motion requires wrapping components - Motion supports keyframes and complex animation sequences out of the box
- React Motion focuses on spring animations, while Motion offers various animation types
Both libraries are valuable tools for React animations, with Motion being more feature-rich and React Motion being lighter and focused on spring physics.
✌️ A spring physics based React animation library
Pros of react-spring
- More flexible API with multiple ways to define animations
- Better performance due to native animation drivers
- Supports a wider range of animation types, including physics-based animations
Cons of react-spring
- Steeper learning curve due to more complex API
- Larger bundle size compared to react-motion
Code Comparison
react-motion:
<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
{({x}) => <div style={{transform: `translateX(${x}px)`}} />}
</Motion>
react-spring:
const props = useSpring({from: {x: 0}, to: {x: 10}})
return <animated.div style={{transform: props.x.interpolate(x => `translateX(${x}px)`)}} />
Both libraries aim to provide smooth animations in React applications, but they differ in their approach and feature set. react-spring offers more flexibility and performance at the cost of complexity, while react-motion provides a simpler API with a focus on spring animations. The choice between the two depends on the specific needs of your project and your familiarity with animation concepts.
🎊 A collection of animations for inline style libraries
Pros of react-animations
- Simpler API with predefined animation styles
- Easy integration with CSS-in-JS libraries
- Lightweight and focused solely on animation keyframes
Cons of react-animations
- Less flexible for complex, physics-based animations
- Limited control over animation timing and behavior
- No built-in support for interrupting or reversing animations
Code Comparison
react-animations:
import { fadeIn } from 'react-animations';
import styled, { keyframes } from 'styled-components';
const fadeInAnimation = keyframes`${fadeIn}`;
const FadeInDiv = styled.div`animation: 1s ${fadeInAnimation};`;
react-motion:
import { Motion, spring } from 'react-motion';
<Motion defaultStyle={{opacity: 0}} style={{opacity: spring(1)}}>
{interpolatingStyle => <div style={interpolatingStyle}>Content</div>}
</Motion>
react-motion offers more granular control over animation physics and behavior, allowing for smoother, more natural-feeling animations. It's particularly useful for interactive animations that respond to user input. However, it has a steeper learning curve and requires more code for basic animations.
react-animations, on the other hand, provides a simpler approach with predefined animation styles. It's easier to use for basic animations and integrates well with CSS-in-JS libraries. However, it lacks the flexibility and fine-tuned control offered by react-motion, making it less suitable for complex, physics-based animations or those requiring precise timing control.
Pros of Motion One
- Supports both React and vanilla JavaScript, offering more flexibility
- Provides a more modern API with better TypeScript support
- Offers a wider range of animation features, including SVG path morphing and scroll-linked animations
Cons of Motion One
- Larger bundle size, which may impact performance for smaller projects
- Steeper learning curve due to more complex API and additional features
- Less focused on React-specific optimizations compared to React Motion
Code Comparison
React Motion:
import { Motion, spring } from 'react-motion';
<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
{({x}) => <div style={{transform: `translateX(${x}px)`}} />}
</Motion>
Motion One:
import { animate } from "motion";
animate(".box", { x: 100 }, { duration: 1 });
Summary
Motion One offers a more versatile and feature-rich animation solution, supporting multiple frameworks and providing advanced animation capabilities. However, it comes at the cost of a larger bundle size and potentially more complex implementation. React Motion, while more focused on React and simpler to use, may be limited in terms of animation options and modern API design. The choice between the two depends on project requirements, performance considerations, and developer preferences.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
React-Motion
import {Motion, spring} from 'react-motion';
// In your render...
<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
{value => <div>{value.x}</div>}
</Motion>
Animate a counter from 0
to 10
. For more advanced usage, see below.
Install
-
Npm:
npm install --save react-motion
-
Bower: do not install with
bower install react-motion
, it won't work. Usebower install --save https://unpkg.com/react-motion/bower.zip
. Or inbower.json
:
{
"dependencies": {
"react-motion": "https://unpkg.com/react-motion/bower.zip"
}
}
then include as
<script src="bower_components/react-motion/build/react-motion.js"></script>
- 1998 Script Tag:
<script src="https://unpkg.com/react-motion/build/react-motion.js"></script>
(Module exposed as `ReactMotion`)
Works with React-Native v0.18+.
Demos
- Simple Transition
- Chat Heads
- Draggable Balls
- TodoMVC List Transition
- Photo Gallery
- Spring Parameters Chooser
- Water Ripples
- Draggable List
Try the Demos Locally
git clone https://github.com/chenglou/react-motion.git
cd react-motion
npm install
- With hot reloading (slow, development version): run
npm start
. - Without hot reloading (faster, production version): run
npm run build-demos
and open the staticdemos/demo_name/index.html
file directly. Don't forget to use production mode when testing your animation's performance!
To build the repo yourself: npm run prepublish
.
What does this library try to solve?
For 95% of use-cases of animating components, we don't have to resort to using hard-coded easing curves and duration. Set up a stiffness and damping for your UI element, and let the magic of physics take care of the rest. This way, you don't have to worry about petty situations such as interrupted animation behavior. It also greatly simplifies the API.
This library also provides an alternative, more powerful API for React's TransitionGroup
.
API
Exports:
spring
Motion
StaggeredMotion
TransitionMotion
presets
Here's the well-annotated public Flow type definition file (you don't have to use Flow with React-motion, but the types help document the API below).
P.S. using TypeScript? Here are the React-motion TypeScript definitions!
Helpers
- spring: (val: number, config?: SpringHelperConfig) => OpaqueConfig
Used in conjunction with the components below. Specifies the how to animate to the destination value, e.g. spring(10, {stiffness: 120, damping: 17})
means "animate to value 10, with a spring of stiffness 120 and damping 17".
-
val
: the value. -
config
: optional, for further adjustments. Possible fields:stiffness
: optional, defaults to170
.damping
: optional, defaults to26
.precision
: optional, defaults to0.01
. Specifies both the rounding of the interpolated value and the speed (internal).
It's normal not to feel how stiffness and damping affect your spring; use Spring Parameters Chooser to get a feeling. Usually, you'd just use the list of tasteful stiffness/damping presets below.
- Presets for {stiffness, damping}
Commonly used spring configurations used like so: spring(10, presets.wobbly)
or spring(20, {...presets.gentle, precision: 0.1})
. See here.
<Motion />
Usage
<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
{interpolatingStyle => <div style={interpolatingStyle} />}
</Motion>
Props
- style: Style
Required. The Style
type is an object that maps to either a number
or an OpaqueConfig
returned by spring()
above. Must keep the same keys throughout component's existence. The meaning of the values:
- an
OpaqueConfig
returned fromspring(x)
: interpolate tox
. - a
number
x
: jump tox
, do not interpolate.
- defaultStyle?: PlainStyle
Optional. The PlainStyle
type maps to number
s. Defaults to an object with the same keys as style
above, whose values are the initial numbers you're interpolating on. Note that during subsequent renders, this prop is ignored. The values will interpolate from the current ones to the destination ones (specified by style
).
- children: (interpolatedStyle: PlainStyle) => ReactElement
Required function.
-
interpolatedStyle
: the interpolated style object passed back to you. E.g. if you gavestyle={{x: spring(10), y: spring(20)}}
, you'll receive asinterpolatedStyle
, at a certain time,{x: 5.2, y: 12.1}
, which you can then apply on yourdiv
or something else. -
Return: must return one React element to render.
- onRest?: () => void
Optional. The callback that fires when the animation comes to a rest.
<StaggeredMotion />
Animates a collection of (fixed length) items whose values depend on each other, creating a natural, springy, "staggering" effect like so. This is preferred over hard-coding a delay for an array of Motions
to achieve a similar (but less natural-looking) effect.
Usage
<StaggeredMotion
defaultStyles={[{h: 0}, {h: 0}, {h: 0}]}
styles={prevInterpolatedStyles => prevInterpolatedStyles.map((_, i) => {
return i === 0
? {h: spring(100)}
: {h: spring(prevInterpolatedStyles[i - 1].h)}
})}>
{interpolatingStyles =>
<div>
{interpolatingStyles.map((style, i) =>
<div key={i} style={{border: '1px solid', height: style.h}} />)
}
</div>
}
</StaggeredMotion>
Aka "the current spring's destination value is the interpolating value of the previous spring". Imagine a spring dragging another. Physics, it works!
Props
- styles: (previousInterpolatedStyles: ?Array<PlainStyle>) => Array<Style>
Required function. Don't forget the "s"!
-
previousInterpolatedStyles
: the previously interpolating (array of) styles (undefined
at first render, unlessdefaultStyles
is provided). -
Return: must return an array of
Style
s containing the destination values, e.g.[{x: spring(10)}, {x: spring(20)}]
.
- defaultStyles?: Array<PlainStyle>
Optional. Similar to Motion
's defaultStyle
, but an array of them.
- children: (interpolatedStyles: Array<PlainStyle>) => ReactElement
Required function. Similar to Motion
's children
, but accepts the array of interpolated styles instead, e.g. [{x: 5}, {x: 6.4}, {x: 8.1}]
(No onRest
for StaggeredMotion because we haven't found a good semantics for it yet. Voice your support in the issues section.)
<TransitionMotion />
Helps you to do mounting and unmounting animation.
Usage
You have items a
, b
, c
, with their respective style configuration, given to TransitionMotion
's styles
. In its children
function, you're passed the three interpolated styles as params; you map over them and produce three components. All is good.
During next render, you give only a
and b
, indicating that you want c
gone, but that you'd like to animate it reaching value 0
, before killing it for good.
Fortunately, TransitionMotion
has kept c
around and still passes it into the children
function param. So when you're mapping over these three interpolated styles, you're still producing three components. It'll keep interpolating, while checking c
's current value at every frame. Once c
reaches the specified 0
, TransitionMotion
will remove it for good (from the interpolated styles passed to your children
function).
This time, when mapping through the two remaining interpolated styles, you'll produce only two components. c
is gone for real.
import createReactClass from 'create-react-class';
const Demo = createReactClass({
getInitialState() {
return {
items: [{key: 'a', size: 10}, {key: 'b', size: 20}, {key: 'c', size: 30}],
};
},
componentDidMount() {
this.setState({
items: [{key: 'a', size: 10}, {key: 'b', size: 20}], // remove c.
});
},
willLeave() {
// triggered when c's gone. Keeping c until its width/height reach 0.
return {width: spring(0), height: spring(0)};
},
render() {
return (
<TransitionMotion
willLeave={this.willLeave}
styles={this.state.items.map(item => ({
key: item.key,
style: {width: item.size, height: item.size},
}))}>
{interpolatedStyles =>
// first render: a, b, c. Second: still a, b, c! Only last one's a, b.
<div>
{interpolatedStyles.map(config => {
return <div key={config.key} style={{...config.style, border: '1px solid'}} />
})}
</div>
}
</TransitionMotion>
);
},
});
Props
First, two type definitions to ease the comprehension.
-
TransitionStyle
: an object of the format{key: string, data?: any, style: Style}
.-
key
: required. The ID thatTransitionMotion
uses to track which configuration is which across renders, even when things are reordered. Typically reused as the componentkey
when you map over the interpolated styles. -
data
: optional. Anything you'd like to carry along. This is so that when the previous section example'sc
disappears, you still get to accessc
's related data, such as the text to display along with it. -
style
: required. The actual starting style configuration, similar to what you provide forMotion
'sstyle
. Maps keys to either a number or anOpaqueConfig
returned byspring()
.
-
-
TransitionPlainStyle
: similar to above, except thestyle
field's value is of typePlainStyle
, aka an object that maps to numbers.
- styles: Array<TransitionStyle> | (previousInterpolatedStyles: ?Array<TransitionPlainStyle>) => Array<TransitionStyle>
Required. Accepts either:
-
an array of
TransitionStyle
configs, e.g.[{key: 'a', style: {x: spring(0)}}, {key: 'b', style: {x: spring(10)}}]
. -
a function similar to
StaggeredMotion
, taking the previously interpolating styles (undefined
at first call, unlessdefaultStyles
is provided), and returning the previously mentioned array of configs. You can do staggered mounting animation with this.
- defaultStyles?: Array<TransitionPlainStyle>
Optional. Similar to the other components' defaultStyle
/defaultStyles
.
- children: (interpolatedStyles: Array<TransitionPlainStyle>) => ReactElement
Required function. Similar to other two components' children
. Receive back an array similar to what you provided for defaultStyles
, only that each style
object's number value represent the currently interpolating value.
- willLeave?: (styleThatLeft: TransitionStyle) => ?Style
Optional. Defaults to () => null
. The magic sauce property.
-
styleThatLeft
: the e.g.{key: ..., data: ..., style: ...}
object from thestyles
array, identified bykey
, that was present during a previous render, and that is now absent, thus triggering the call towillLeave
. Note that the style property is exactly what you passed instyles
, and is not interpolated. For example, if you passed a spring forx
you will receive an object like{x: {stiffness, damping, val, precision}}
. -
Return:
null
to indicate you want theTransitionStyle
gone immediately. AStyle
object to indicate you want to reach transition to the specified value(s) before killing theTransitionStyle
.
- didLeave?: (styleThatLeft: {key: string, data?: any}
) => void
Optional. Defaults to () => {}
.
styleThatLeft
: the{key:..., data:...}
that was removed after the finished transition.
- willEnter?: (styleThatEntered: TransitionStyle) => PlainStyle
Optional. Defaults to styleThatEntered => stripStyle(styleThatEntered.style)
. Where stripStyle
turns {x: spring(10), y: spring(20)}
into {x: 10, y: 20}
.
-
styleThatEntered
: similar towillLeave
's, except theTransitionStyle
represents the object whosekey
value was absent during the lastrender
, and that is now present. -
Return: a
defaultStyle
-likePlainStyle
configuration, e.g.{x: 0, y: 0}
, that serves as the starting values of the animation. Under this light, the default provided means "a style config that has the same starting values as the destination values".
Note that willEnter
and defaultStyles
serve different purposes. willEnter
only triggers when a previously inexistent TransitionStyle
inside styles
comes into the new render.
(No onRest
for TransitionMotion because we haven't found a good semantics for it yet. Voice your support in the issues section.)
FAQ
- How do I set the duration of my animation?
Hard-coded duration goes against fluid interfaces. If your animation is interrupted mid-way, you'd get a weird completion animation if you hard-coded the time. That being said, in the demo section there's a great Spring Parameters Chooser for you to have a feel of what spring is appropriate, rather than guessing a duration in the dark.
- How do I unmount the
TransitionMotion
container itself?
You don't. Unless you put it in another TransitionMotion
...
- How do I do staggering/chained animation where items animate in one after another?
See StaggeredMotion
- My
ref
doesn't work in the children function.
React string refs won't work:
<Motion style={...}>{currentValue => <div ref="stuff" />}</Motion>
This is how React works. Here's the callback ref solution.
Top Related Projects
Declarative Animations Library for React and React Native
Open source, production-ready animation and gesture library for React
✌️ A spring physics based React animation library
🎊 A collection of animations for inline style libraries
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot