The article compares two popular React animation libraries, React-Spring and Framer Motion, by converting examples from one library to the other to demonstrate their unique features and animation strategies.
Abstract
The article delves into the comparison of React-Spring and Framer Motion, two animation libraries for React, each with its own approach to creating animations. React-Spring utilizes spring physics to mimic real-life movement, while Framer Motion employs a more traditional duration-and-location method. The author explores the ease of converting animations between the two libraries by providing practical examples, such as transforming a GrowBall drag-and-scale animation from Framer Motion to React-Spring and vice versa. The conversion process highlights the strengths and limitations of each library, such as Framer Motion's built-in Gestures API for handling user events and React-Spring's reliance on spring physics for natural motion. The article also addresses the challenges faced when replicating complex multi-stage transitions, particularly the lack of an 'update' state in Framer Motion's variants compared to React-Spring's useTransition hook.
Opinions
The author finds that Framer Motion's event APIs, known as Gestures, simplify the handling of user events, making it an attractive choice for developers familiar with traditional animation techniques.
Despite initial concerns, the author discovers that converting a drag animation from Framer Motion to React-Spring is made straightforward with the use of the 'react-with-gesture' library.
The author acknowledges that while Framer Motion's keyframes can handle multi-stage transitions, it requires more detailed syntax and a deeper understanding of CSS, which can be more complex than React-Spring's spring physics approach.
React-Spring's useSpring and useTransition hooks are highlighted for their ability to handle dynamic animations and multiple transitions smoothly.
The author suggests that the choice between Framer Motion and React-Spring should be based on the desired look and feel of the animations, as well as the specific animation needs of the project.
The author expresses a preference for Framer Motion for quick and familiar duration-and-location animations and for React-Spring when seeking a natural, spring-physics-based animation style.
React-Spring vs Framer Motion: Comparing Examples in Two Animation Libraries
Framer Motion and react-spring both solve unique animation challenges and execute with high performance.
Framer Motion uses the more traditional duration-and-location approach. Most developers likely have experience with this animation strategy and it will feel familiar.
React-Spring approaches animations using spring-physics. This is a well-executed attempt to make animations feel and behave like real-life movement.
I was curious: how difficult is it to convert an animation from Framer Motion to react-spring? How about from react-spring to Framer Motion?
GrowBall Example: Converting Framer Motion drag and useMotion to React-Spring useSpring
Framer Motion has a built-in suite of event APIs called Gestures. These APIs make handling certain user events easy and dynamic. In the Grow Ball example, the original Framer Motion version used drag to set drag constraints when dragging horizontally. Then useMotion and useTransition converted the x value to a scale for the ball SVG.
I expected the drag API would be difficult to replicate in react-spring. However, a third-party library called ‘react-with-gesture’, which is commonly used with react-spring, made the conversion painless.
const [bind, { delta, down }] = useGesture();
const { x } = useSpring({
x: down ? delta[0] : 0
});
useGesture provides a way to track ‘down’ gestures and the change in x or y position. The hook is simply bound to a div, as shown below.
When down is triggered, useSpring captures the value and makes it available for use as an AnimatedValue. In this example, interpolate is called on x and it is transformed and outputs a value between 0.1 and 1, which is then used as the scale value. The original x value is also used to update the <animated.div />x value.
I recommend that you take a look at the react-spring codesandbox before taking a look at my below example in Framer Motion because, admittedly, I couldn’t match the exact timing and sequencing in my conversion.
My version after converting to Framer Motion:
The react-spring useTransition hook has two significant features that I need to replicate. First, it monitors four states: from, enter, leave, and update . Second, it easily handles multiple transitions per state. An example of this from the original react-spring Codesandbox is below:
These are the dynamic kinds of functionality that I need to replicate in my conversion to Framer Motion.
After investigating the potential tools within Framer Motion, I settled on using <AnimatePresence /> and variants to handle the animations. <AnimatePresence /> allows for the animation of components that have left the DOM tree, which is needed for exit animation.
I encountered two significant challenges. First, the variant states in Framer Motion are limited to initial, enter, and exit. The missing update means that animating updates (but not additions or subtractions) to our array values will have to be handled manually. Second, Framer Motion relies on keyframes to handle multi-stage transitions. This requires more syntax, more exact customization (such as setting animation times), and simply more knowledge of the underlying css. These are the exact things react-spring is designed to avoid by relying on lifelike spring animations instead of duration-and-location animations.
The above replicates most of the original react-spring animation. The timing isn’t the exact same, but more importantly, the update state is still missing. I might be able to compensate for this via more keyframes or perhaps through a more nuanced populating of the string array that hold the values getting animated.
The variants are simple to plug into the <AnimatePresence/> component.
Comparing React-Spring and Framer Motion
While there are nuances to each library, there are also many areas where they overlap. Most notably:
Motions in Framer Motion are the corollary to Render-Props in react-spring — they have a different focus but each give highly specialized functionality to the libraries
Framer Motion useTransform is the corollary to react-spring interpolation
Framer Motion Gestures are the corollary to react-spring + react-with-gestures
Framer Motion drag is the corollary to react-spring clamp
Framer Motion animate is the corollary to react-spring useSpring
In fact, many of the examples in the react-spring docs are reminiscent of examples in the Framer Motion docs.
Naturally, there is a difference in the underlying philosophy of react-spring and Framer Motion. Each library was created to solve a different problem or provide certain features that the creators wanted.
I think Framer Motion will be best when I want to create animations quickly, because duration-and-location animation is what I have prior experience with. I would tend towards react-spring if I want spring physics look-and-feel in my project. Also, I would consider Framer Motion Gestures and react-spring + react-with-gesture and consider if either out-of-the-box animation suite had the exact event I needed.
When choosing a library for a project, consider the end goal of the project, the look and feel that you want your animations to have, and don’t be afraid to try something new.