Animating children

Traditionally, coordinating animation across multiple children has been an involved process. Especially with React.

With Pose, it’s as simple as animating just one. It looks like this:

const Parent = posed.ul();
const Child = posed.li();

({items}) => (
  <Parent pose="poseName">
    {items.map(item => <Child item={item} />)}
  </Parent>
)

Whenever a posed component changes pose, that change is communicated throughout all of its children posed components via React’s context API. So even if they’re not direct children, they still update accordingly.

This makes it super-simple to, for instance, make page-wide route transitions.

Setup

To demonstrate animating children, we’re going to create this sidebar animation (if the animation has already played, refresh the iframe):

Follow along by forking this CodeSandbox.

Poses

First, we need to describe two poses, “open” and “closed”, for both the sidebar and the items within it.

At the top of your index.js, create your posed components:

const Sidebar = posed.ul({
  open: { x: '0%' },
  closed: { x: '-100%' }
});

const Item = posed.li({
  open: { y: 0, opacity: 1 },
  closed: { y: 20, opacity: 0 }
});

Render

In our render function, replace return null with our Sidebar, setting our pose prop to either the open or closed poses defined above:

return (
  <Sidebar className="sidebar" pose={isOpen ? 'open' : 'closed'} />
);

Now when the isOpen is true, our sidebar animates out. All we have to do to also animate the Item components is add those as children:

return (
  <Sidebar className="sidebar" pose={isOpen ? 'open' : 'closed'}>
    <Item className="item" />
    <Item className="item" />
    <Item className="item" />
    <Item className="item" />
  </Sidebar>
);

We only provide pose to Sidebar, yet Item components also animate!

Scheduling animations

Currently, our children animations are being fired at the exact same time as the parent. But, often we’d prefer the child animations to be delayed or staggered.

Luckily, we’ve got properties for that!

delay

The delay property can be used to delay the animation on the current poser, without affecting the execution of child animations.

So by setting delay: 300 on the sidebar’s closed pose, the children will all animate out before the sidebar itself.

const Sidebar = posed.ul({
  open: { x: '0%' },
  closed: { x: '-100%', delay: 300 }
});

delayChildren

Conversely, the delayChildren property can be used to delay all the children animations.

By setting delayChildren on the sidebar’s open pose, we can animate the sidebar out and then animate the children in:

const Sidebar = posed.ul({
  open: { x: '0%', delayChildren: 200 },
  closed: { x: '-100%', delay: 300 }
});

staggerChildren

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:

const Sidebar = posed.ul({
  open: {
    x: '0%',
    delayChildren: 200,
    staggerChildren: 50
  },
  closed: { x: '-100%', delay: 300 },
  initialPose: 'closed'
});

staggerDirection

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).

beforeChildren/afterChildren

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