Animations help bring an application to life. When done properly, they can be an essential part of the user experience and accessibility.

Adding animations to your website doesn't need to be a daunting task, in this post I'll provide a brief overview of the different options available to implement animations on the web. Specifically, I'll introduce you to Popmotion Pose, a declarative way of creating UI animations in React and React Native along with different features of this library by building a simple example.

CSS-Animations

CSS Animations

CSS animations are probably the most common and intuitive way of implementing animations on the web. Using the transition or animation properties (or sub-properties) animations can be implemented in a relatively easy manner without having to use JavaScript.

CSS animations are not without their problems and lack the fine-grained control that JavaScript offers. It is also hard to build certain kinds of animations, such as spring-like movement. If you wanted to build complex animations where you would like to have more control over aspects of animation like sequencing, timeline, realism, etc, then JavaScript animations are the way to go.

JavaScript Animations

There are several libraries in JavaScript that allow you to build animations in a more imperative fashion such as GSAP, anime.js and velocity.js. While these libraries offer a lot of power and control over the kinds of animations that you can implement, they are not built with React in mind and don’t share the same declarative approach that React has.

If you want to be able to leverage the declarative syntax of React and have access to the component lifecycle hooks - you might want to look into animation libraries created with React in mind.

React Animations

React has an add-on component called ReactTransitionGroup that is a low-level API for animation and ReactCSSTransitionGroup that is a high-level API for performing CSS transitions and animations in an easy manner when a component mounts or unmounts. These components can be helpful when building animations in React that need to be executed on lifecycle updates, however they don’t afford a lot of control or realism. This is where Popmotion Pose comes into play. Pose is a declarative motion system for React, React Native, and vanilla JS by Popmotion. On its website, Pose claims to be almost as easy to use as CSS animations. Let’s see if that’s the case by building a simple example.

You can get started with React-Pose by installing react-pose from npm and importing the posed function to your file.

import posed from "react-pose";

The next step is creating a config JS object that defines a state name as a key, and the values that you would like to apply for that state as the value for that key.

Here in this object, we are defining two distinct states labeled off and on where the properties that we would like to animate for those states are defined in the corresponding javascript objects.

const config = {
  off: {
    opacity: 0.5,
    scale: 1
  },
  on: {
    opacity: 1,
    scale: 2
  }
};

Then we can create a component using the posed import. Using posed you can either create a component that wraps the desired element (eg. posed.div) or you can convert existing components to work with Pose animations (eg. posed(Component)). If you have ever used styled-components you will notice that this is really similar to how styled factory function works in styled-components.

Let’s create a component that wraps a div element using posed and the config object that we have created.

const Box = posed.div(config);

Now you can pass a pose prop to this Box component that will specify which animation state that this box is in. Ideally, you would want to have the pose value change based on some state so that your component can be animated in between these pose changes whenever the state changes.

<Box pose={this.state.hovered ? "on" : "off"}>

Here is the complete example. You’ll notice that the transition type for the animation is configured automatically by Pose, which is a spring in this case.

Edit react-pose-1

React-Animations

The config object is where you get to set up the various properties of the animation. As you have already seen, it is possible to configure animation settings for multiple properties. You could also define a transition property to configure things like easing style, animation delay, animation duration, transition type, etc.

Let’s enhance our existing config properties to illustrate this.

const config = {
  off: {
    opacity: 0.5,
    scale: 1
  },
  on: {
    opacity: 1,
    scale: 2,
    transition: {
      type: "spring",
      stiffness: 500,
      delay: 200
    }
  }
};

spring-transition-animation

Here I’ve applied a transition of type ‘spring’ to both opacity and scale with spring stiffness set up to 500 which results in a more pronounced spring motion along with a delay of 200ms. You will notice that these transition options are applied to both opacity and scale properties. You can explicitly specify which property you would like to affect by passing it as a key to the transition object.

In the example below, the spring settings are only applied to the scale property animation.

const config = {
  off: {
    opacity: 0.5,
    scale: 1
  },
  on: {
    opacity: 1,
    scale: 2,
    transition: {
      scale: {
        type: "spring",
        stiffness: 500,
        delay: 200
      }
    }
  }
};

Now, let’s look at a more involving example:

https://codesandbox.io/s/9lk90mk1r4

property-animation

Here are the most important highlights in this example:

FLIP Animations

When it comes to animation, not all properties are created equal. Properties such as position, rotation, scale and opacity are cheaper to update since they don’t cause a layout or painting change in the pixel rendering pipeline of the browser.

There is a JavaScript technique called FLIP that you can use to animate layout-breaking CSS Properties such as width, height or top in a performant manner. Implementation of this technique can be rather cumbersome if done manually. Luckily, when using Pose you just need to set the flip property to true inside your configuration object when animating these properties to utilize the FLIP technique.

const configBox = {
  off: {
    width: 150,
    height: 150,
    flip: true,
    background: "#69a7c2"
  },
  on: {
    width: "90vw",
    height: "90vh",
    flip: true,
    background: "#035D75"
  }
};

Also, notice how the background-color is animated in this example as well.

PoseGroup

In order to apply animation to a component when it mounts or dismounts you need to make use of the PoseGroup component. From the Popmotion documentation:

The PoseGroup component manages enter and exit animations on its direct children as they enter and exit the component tree.

In my example, I have a component called Message that only renders if a property called displayMessage is true. Since the Message component is wrapped inside a PoseGroup component it receives an enter and an exit pose which we can define a corresponding animation state inside our configuration object for the Message.

const configMessage = {
  enter: {
    opacity: 1
  },
  exit: {
    opacity: 0,
    transition: { duration: 100 }
  }
};

Child Animations

The Content.js is the posed component that contains various child components. By setting two simple properties on the configuration object for this component we are able to delay and stagger the animation of each child component.

const configContent = {
  off: {
    opacity: 0
  },
  on: {
    opacity: 1,
    delayChildren: 250,
    staggerChildren: 100
  }
};

As you can see in these examples Popmotion Pose has a very intuitive interface that makes it really easy to use. It has a declarative API that allows it to integrate well with a React codebase and makes it straightforward to fine-tune your animations with the extensive properties that it provides. Most importantly, it has an excellent documentation with a lot of illustrative examples. Popmotion Pose has a lot of great features that enables for a great developer and user experience.