Archive » Animations (pre X22) » Chaining animations

Chaining animations

Warning: These pages are from before the launch of Framer X22 and are about the older animation API. These animations might still work in the current version of Framer but are officially deprecated. Learn about the current animation API here.

You can attach animations to other animations and have them run consecutively with a bit of asynchronous JavaScript code.

Let’s say that I want a frame to animate down, and then back up. I might think of something like this:

export const MoveDownAndUpAgain: Override = () => {
  return {
    top: data.yPosition,
    onTap() {
      // Move down
      animate(data.yPosition, 620);
      // Move back up
      animate(data.yPosition, 67);
    }
  };
};

Alas, that would have been too easy.

The two animations will start at the same time, and in this example, nothing will happen (because they cancel each other out).

To chain animations, you have to make one animation wait for the other, and that can only happen inside an asynchronous function.

But fortunately, we have a function that already contains our animations: onTap(). We make it asynchronous by putting async in front of it.

export const MoveDownAndUpAgain: Override = () => {
  return {
    top: data.yPosition,
    async onTap() {
      ...

Then inside the function, you write await before a statement that should be waited for, in this case: our first animation.

export const MoveDownAndUpAgain: Override = props => {
  return {
    top: data.yPosition,
    async onTap() {
      await animate(data.yPosition, 620).finished;
      animate(data.yPosition, 67);
    }
  };
};

And that would (often) be enough, but because our statement is an animation we have to add .finished at the end of the animate() call.

Now the second animation will start when the first one completed.

Returning to the start position

I added one more detail: To always have the correct start position, I get the current top from the frame’s props and save I it in a variable called startPosition.

And I animate back to startPosition in the second animation.

export const MoveDownAndUpAgain: Override = props => {
  data.yPosition.set(props.top);
  const startPosition = props.top;
  return {
    top: data.yPosition,
    async onTap() {
      await animate(data.yPosition, 620).finished;
      animate(data.yPosition, startPosition);
    }
  };
};
download this project