question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[QUESTION] How to Delay Children Animations with AnimatePresence

See original GitHub issue

Describe the bug I am using AnimatePresence on a simple example to fade in pages as they are mounted/unmounted. This works as expected. What I am struggling with is delaying the individual children animations on each page to wait until after the fade has completed first.

Using Pose and the PoseGroup I accomplished this with code similar to this:

const Transition = posed.div({
  enter: {
    opacity: 1,
    transition: { duration: 300 },
    delay: 300,
    beforeChildren: true
  },
  exit: { opacity: 0, transition: { duration: 300 } }
});

With Framer Motion and AnimatePresence my code looks similar to this :

const variants = {
  initial: {
    opacity: 0,
  },
  enter: {
    opacity: 1,
    transition: {
      duration: .3,
      delay: .3,
      when: 'beforeChildren',
    },
  },
  exit: {
    opacity: 0,
    transition: { duration: .3 },
  },
}

To Reproduce Code Sandbox - https://codesandbox.io/s/github/ryanwiemer/gatsby-using-page-transitions Github Repo - https://github.com/ryanwiemer/gatsby-using-page-transitions/blob/master/src/components/Layout.js

  1. Go to https://transitions.netlify.com/
  2. Navigate between the pages to see the basic page fade.
  3. Navigate to the “Animated” page. The list of items should do a stagger fade in but that animation occurs at the same time as the page fade so you don’t see it.

Expected behavior I expect the top level page fade to occur followed by the children animations. Right now all animations are occurring at the same time.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:17

github_iconTop GitHub Comments

33reactions
thebetternewtcommented, May 15, 2020

I’ve been battling with this issue too. I found that if you make your child variant keys exactly the same names as your parent variant keys (in my case “enter” and “exit”), then it works!

Do not add “initial”, “animate”, or “exit” props on the child components – only the relevant “variants” prop, like so:

import React from 'react';
import styled from 'styled-components';
import { motion, Variants } from 'framer-motion';

const containerVariants: Variants = {
  enter: {
    x: 0,
    opacity: 1,
    transition: {
      when: 'beforeChildren',
      staggerChildren: 0.4,
    },
  },
  exit: { x: -300, opacity: 0 },
};

const childVariants: Variants = {
  enter: {
    x: 0,
    opacity: 1,
  },
  exit: {
    x: -20,
    opacity: 0,
  },
};

const childVariants2: Variants = {
   enter: {
    x: 0,
    opacity: 1,
    color: 'red',
  },
  exit: {
    x: -20,
    opacity: 0,
    color: '#000',
  },
};

export const Menu = () => {
  return (
    <MenuWrapper
      variants={containerVariants}
      initial="exit"
      animate="enter"
      exit="exit"
    >
      <motion.h2 key="heading" variants={childVariants}>
        My Menu
      </motion.h2>

      <motion.h3 key="subheading" variants={childVariants}>
        Section 1
      </motion.h3>

      <motion.h3 key="subheading" variants={childVariants2}>
        Section 2
      </motion.h3>
    </MenuWrapper>
  );
};

const MenuWrapper = styled(motion.div)`
  position: absolute;
  top: 0;
  bottom: 0;
  width: 300px;
  padding: 20px 1rem;
  background-color: #111;
  color: #fff;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
  z-index: 8;

  h2 {
    margin: 0 0 1rem;
  }
`;

Note that I’m rendering this component inside of a <AnimatePresence> component with React Router Dom:

import React from 'react';
import { Route, Switch, useLocation, BrowserRouter } from 'react-router-dom';

import { AnimatePresence, motion } from 'framer-motion';
import { Menu } from './components/layout/Menu';

function App() {
  const location = useLocation();

  return (
      <AnimatePresence exitBeforeEnter>
        <Switch location={location} key={location.pathname}>
          <Route exact path="/">
            <Menu />
          </Route>
        </Switch>
      </AnimatePresence>
  );

export default () => (
  <BrowserRouter>
    <App />
  </BrowserRouter>
);
13reactions
rmacycommented, Mar 14, 2020

This is an issue I’m running into. My use-case is a sidebar that expands out and needs to delay the rendering of its children until it’s full expanded.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How do I delay animate, not whileOver or WhileTap in framer ...
I believe you can add a transition key to the animate object itself: animate={{ opacity: 1, y: 0, rotate: 0, transition: { type:...
Read more >
AnimatePresence | Framer for Developers
Exit animations. AnimatePresence works by detecting when direct children are removed from the React tree. Any motion components contained by the removed child...
Read more >
Exit animation with `framer-motion` demystified
It's here that comes the AnimatePresence component that will keep the unmounted children in a reference and at each render detects components ...
Read more >
Advanced animation patterns with Framer Motion
A deep dive into Framer Motion's propagation, exit transitions and layout animation patterns through curated examples and interactive ...
Read more >
Many tiny animations combined into one, nice side menu.
If I set staggerChildren to 0.015, first child will animate immediately, second with delay of 0.015s, third with 0.030s delay, and so on....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found