React Pose for easy and amazing animations

A quick quide to using Pose animation library with React and producing beautiful UI animations

Published: 27 November 2019

react pose animation javascript react-pose 

Install


npm install react-pose --save

Basic Usage


Steps are as follows:

  • Create a new component with React Pose
  • Declare some poses or states on this component
  • Use the component in JSX
  • Declare conditions in JSX on when to show the different poses/states
Step 1

To make things work we must "recreate" any basic HTML element that we are trying to animate like div, span, etc with React Pose as follows:

import posed from "react-pose"

const NewPosedDiv = posed.div() //creates a div component which can be animated
Step 2

This new div can now be given some poses aka states which React Pose will show under different situations.

import posed from "react-pose"

const NewPosedDiv = posed.div({
  shown: { opacity: 1 }, // we can stipulate in JSX when to apply this pose
  hidden: { opacity: 0 }, // or this pose
})
Step 3

NewPosedDiv can now be used as a div inside our JSX like so:

//always declare posed components outside render/return block
const NewPosedDiv = posed.div()

const MyComponent = () => {
  return (
    <NewPosedDiv>
      <h1>I am a heading</h1>
      <p>I am some random paragraph</p>
    </NewPosedDiv>
  )
}

export default MyComponent

NOTE: Make sure that any new elements created with React pose should be declared outside of the render function (in class based components) and outside the return statement (in functional components)

Pose works by detecting changes in the state. If a component is declared outside the render or return blocks, it won't be re-rendered as a brand new component with each render cycle. This will allow pose to detect any changes and show necessary animations/poses.

Step 4

Declare the conditions under which different poses should be applied.

Lets say MyComponent receives a boolean prop startAnimation, which dictates when to show the animation.

To achieve this, we can pass a pose prop to the NewPosedDiv

const MyComponent = props => {
  return (
    <NewPosedDiv pose={props.startAnimation ? "shown" : "hidden"}>
      <h1>I am a heading</h1>
      <p>I am some random paragraph</p>
    </NewPosedDiv>
  )
}

We have now stipulated that if startAnimation is true, we want the shown pose to be applied to our NewPosedDiv, otherwise use hidden pose.

Also, NewPosedDiv doesn't need to be a root level element, we could have just as easily nested it inside a normal div like so:

const MyComponent = props => {
  return (
    <div>
      <p>Paragraph doing not much</p>
      <NewPosedDiv pose={props.startAnimation ? "shown" : "hidden"}>
        <h1>I am a heading</h1>
        <p>I am some random paragraph</p>
      </NewPosedDiv>
    </div>
  )
}

As a side note, we haven't declared what the animation will look like. We only provided two states and React Pose took care of the rest behind the scenes.

By default, it uses a tween type animation which looks amazing.

Advanced Usage


We can add as many animatable css properties as we like to a single pose object:

const NewPosedDiv = posed.div({
  shown: {
    opacity: 1,
    background: "#af55b7", //make sure to use HEX or RGB values only
    height: "100vh",
  },
  hidden: {
    opacity: 0,
    background: "#b4b1e8", //make sure to use HEX or RGB values only
    height: 0,
  },
})

We can also add a transition key to any pose to indicate the duration, delay, type and many other properties of the overall pose as well as of individual properties:

const NewPosedDiv = posed.div({
  shown: {
    opacity: 1,
    //applied to overall pose
    transition: {
      duration: 2000,
      delay: 300,
      type: "spring",
    },
  },
  hidden: {
    opacity: 0,
    //OR to each prop
    transition: {
      opacity: { duration: 1000, delay: 100 }, //each prop inidividually
      default: { duration: 500 }, // or a default for applied to every prop
    },
  },
})

transition can also be a function and runs once for each css property of the pose. It also receives an object as an argument which contains some default built-in props as well as any props we pass to the posed component:

Some of the built in props:

key - the name of the current property that is being looped over

to - value to set for the “key” that is currently being looped over

from - value to override of the current key (This is the old value which is to be replaced)

In either case, it must still return an object containing properties as shown in above code snippets.

const NewPosedDiv = posed.div({
  shown: {
    width:(props) => `${props.width + 10}%`, //each key can be a function to access props
    transition: (props) => {
      return {
        duration: 500,
        to: props.key === "width"
              ? props.width + "%" //accessing the passed width prop
              : props.to
      }
    },
  },
  hidden:{ width:0% }
})

const MyComponent = props => {
  return (
    <NewPosedDiv
      pose={props.startAnimation ? "shown" : "hidden"}
      width="50" //passing our own width prop
    >
      <h1>I am a heading</h1>
      <p>I am some random paragraph</p>
    </NewPosedDiv>
  )
}

Components created with React Pose, also receive some built in states like "enter" or "exit"

These can be useful when we are trying to animate a whole page or a whole route inside react router.

const NewPosedDiv = posed.div({
  enter: { y: 0, opacity: 1, delay: 300 },
  exit: {
    y: 50,
    opacity: 0,
    transition: { duration: 200 },
  },
})

Animating Children


We can also animate children of any posed components in 2 ways:

(1) Make all children posed components as well

//Main posed component
const PosedSideMenu = posed.div({
  visible: { width: "30%", delayChildren: 200, staggerChildren: 50 },
  hidden: { width: "0%" },
})

// list of posed components as children
const PosedSideMenuItems = posed.li({
  show: {
    opacity: 1,
    transition: ({ delay }) => ({ delay, duration: 500 }),
  },
  hide: { opacity: 0 },
})

//Component to render at the end
const Menu = props => {
  return (
    <PosedSideMenu pose={props.show ? "visible" : "hidden"}>
      <ul>
        {["First", "Second", "Third"].map((item, i) => (
          <PosedSideMenuItems key={item} pose={props.show ? "show" : "hide"}>
            {item}
          </PosedSideMenuItems>
        ))}
      </ul>
    </PosedSideMenu>
  )
}

NOTE: Rather than animating all the children in at once, it’s possible to stagger them in individually. The staggerChildren prop can be used to determine the delay between each one, starting from after the delayChildren duration.

staggerDirection can be used to determine which order we stagger over the children in. It can either be 1 (first to last, default), or -1 (last to first).

Setting either beforeChildren or afterChildren props to true will make the parent animation play before or after any children animations.

(2) PoseGroup

Use PoseGroup to animate all children components regardless of whether any of them are posed components or not. PoseGroup is a component which wraps all the other components and always needs to be mounted while the children get mounted/unmounted according to state changes. This is why it forms the root component in cases for full page animations.

So, the above menu component can be re-written as:

import posed, { PoseGroup } from "react-pose"

//Component to render at the end
const Menu = props => {
  return (
    <PoseGroup>
      <PosedSideMenu pose={props.show ? "visible" : "hidden"}>
        {["First", "Second", "Third"].map((item, i) => (
          <li key={item}>{item}</li>
        ))}
      </PosedSideMenu>

      {/* could add more children if needed */}
      {/*
         <PosedSideMenu pose={props.show ? "visible" : "hidden"}>
        {["Fourth", "Fifth", "Sixth"].map((item, i) => (
          <li key={item}>{item}</li>
        ))}
        */}

      </PosedSideMenu>
    </PoseGroup>
  )
}

React Pose in depth reference guide here

Github Repo with sample code here