React simplifies the conceptual model of a UI by making it a function of state, but introducing animation complicates things by adding time as a factor. In my time working with React, I’ve tended to stick to CSS transitions and animations with the aid of CSSTransitionGroup, finding other animation techniques a bit hard to wrap my mind around. But obviously, CSS has its limits, and recently when thinking about how to implement a simple sequential animation in React, I decided it was time to explore my options. So, with this in mind I set a challenge for myself – reproduce the following animation using five different React animation libraries:
This animation has a number of features that make it ever-so-slightly complex to implement, including:
- Nested enter and leave transitions: The parent grid animates in, and then when that animation is complete, the cards enter one by one. On leave, the cards animate out first, then the grid.
- A slightly fancy (read: slightly annoying) elastic easing when the grid enters.
- Staggered animation for the cards as they enter and exit.
- Different, opposite animations for enter and exit transitions, with different timings.
In order to keep the focus on developer ease of use rather than other factors, I decided to limit myself to a about an hour to an hour-and-a-half to familiarize myself with each library’s API and get as close as possible to building the complete animation. Once the time was up, I’d just post whatever I managed to accomplish and compare it with the animations I built in the other React libraries I tried. (If you just want to see what ended up being my favorite, skip to the last section in in this post.)
- This lightweight wrapper over d3’s interpolate function has an intuitive API.
- d3-interpolate will be familiar already to anyone who’s played with d3, and offers a lot of powerful interpolation and easing options.
- The library provides a stagger utility for multiple sequential animations.
- It’s difficult to sequence multiple discrete animations or delay updates of other components until animations are complete (no callback functionality is provided, and no delay utilities).
- It’s also difficult from the current docs to figure out how to animate a single element’s enter and exit (although that could be a result of my misunderstanding!)
- You need to apply the style attributes yourself, which means you need to take care of vendor prefixing.
- The animation I created in the time limit has several problems, and I couldn’t get the leave animation working at all.
This is the cool kid on the block, boasting physics-based, interruptible animation. However, I’m appraising it in terms of how easy it was to create the simple animation discussed above, so I didn’t engage with some of its powerful functionality.
- The spring-based animation looks great!
- This was by far the most confusing library to get up and running, with the most code that needed to be written by the developer. I know my example doesn’t do it justice.
- I was not able to get the StaggeredMotion and TransitionMotion components to play nice together– it seems other people have maybe also had similar difficulties.
- Specifying spring parameters instead of animation timing durations is a shift in thinking and I’m not convinced it’s necessary for many animations.
This library is a wrapper on top of react-motion.
- Very little code is necessary to write thanks to this library’s extremely simple API, so it’s really easy to get started.
- This is meant for only simple use cases and cannot handle staggering or timing at all, which meant it wasn’t suitable for the animation I was trying to achieve.
This library is a React wrapper on the well-known VelocityJS library. I was able to get a (somewhat) working animation much faster than with the previous three libraries, although ultimately I was not able to get the nested leave transition working.
- The library API will be familiar to anyone who has used VelocityJS before, and the components use a similar API to ReactTransitionGroup.
- Offers a ton of functionality out of the box: easing options, stagger options, pre-registered animations, easy ways to specify delays, durations, etc.
- Provides a nicely declarative way to add reusable animations (VelocityHelpers.registerEffect).
- The provided code examples helped me get up and running more quickly.
- I found the actual documentation slightly confusing, since it mostly delegates to the VelocityJS documentation, and didn’t answer some questions I had about the React-specific implementation.
- The abstraction on top of the ReactTransitionGroup did leave me frustrated when I was not able to get the leave transitions to work as I wanted them to.
- My code ended up being pretty verbose.
Winner: Reaction-transition-group and GSAP or anime.js
- This was by far my favorite method, offering the full power of the ReactTransitionGroup API to react to component lifecycle events, as well as the full power of GSAP/anime.js, which are both extensively featured animation libraries.
- This method took the least time to set up, required me to write very little code (especially the GSAP example!), and was the only version of the animation I got to work within the time limit.
- Since GSAP and anime.js are manipulating the DOM, you need to be careful to add keys to animating elements, and it’s possible that a state update while an animation is in progress could result in unforeseen consequences. Tools such as the react-gsap-enhancer promise to avoid this issue, although in practice I’m not sure how necessary that is for simple animations that are just manipulating style attributes on elements. You might notice if you rapidly toggle the GSAP animation it gets confused due to animations continuing on even when the state is changed, which is something I managed to fix in the anime.js example, where I properly cancel the in-progress animation and reset the styles on each animation.
- The GSAP library is not currently structured to take advantage of ES2015 imports and uses global variables, which is why I slightly preferred anime.js for this example despite GSAP’s superior feature set and performance.
In the future, I plan on using GSAP or anime.js along with ReactTransitionGroup for any animations where a simple CSS animation won’t suffice, since it was so much easier to get working than the other libraries I tried, even though this approach requires you to manually handle accessing the DOM directly, track components with keys, and interrupt in-progress animations if necessary. I would like to examine the performance implications of the approach I’ve chosen, and also look further into react-motion at some point, since despite its complexity it is clearly very powerful.
Have a question about how we use React or other front end technologies? Send an email to Alex.