Motion: Nesting issue with AnimatePresence

Created on 11 Mar 2020  路  2Comments  路  Source: framer/motion

I'm trying to create a simple modal which requires two animations: one for the backdrop and the other for the modal itself.
When the modal appears both animations run fine, but when I close the modal only the backdrop's animation is run.

Here's the sandbox: https://codesandbox.io/s/nostalgic-architecture-5elz2

Relevant Code:

import React from "react";
import { AnimatePresence, motion } from "framer-motion";

export default function({ children, isOpen, onClose }) {
  const modalVariants = {
    open: {
      translateY: 0
    },
    closed: {
      translateY: -60
    }
  };

  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          key="backdrop"
          className="backdrop"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
        >
          <motion.div
            key="modal"
            className="modal"
            initial="closed"
            animate={isOpen ? "open" : "closed"}
            variants={modalVariants}
          >
            <div>{children}</div>
            <button onClick={onClose}>Close</button>
          </motion.div>
        </motion.div>
      )}
    </AnimatePresence>
  );
}

Is this expected behavior? and if so is there any other solution for this situation?
Thanks.

bug

Most helpful comment

After looking through the examples, the accordions one seems to use nesting with an AnimatePresence, but it is utilizing propagation. So I adjusted my code to do the same and it worked:

import React from "react";
import { AnimatePresence, motion } from "framer-motion";

export default function({ children, isOpen, onClose }) {
  const backdropVariants = {
    open: {
      opacity: 1
    },
    closed: {
      opacity: 0
    }
  };
  const modalVariants = {
    open: {
      translateY: 0
    },
    closed: {
      translateY: -60
    }
  };

  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          key="backdrop"
          className="backdrop"
          initial={"closed"}
          animate={isOpen ? "open" : "closed"}
          exit={"closed"}
          variants={backdropVariants}
        >
          <motion.div key="modal" className="modal" variants={modalVariants}>
            <div>{children}</div>
            <button onClick={onClose}>Close</button>
          </motion.div>
        </motion.div>
      )}
    </AnimatePresence>
  );
}

Here's the modified sandbox: https://codesandbox.io/s/hardcore-stonebraker-8zsd7

But I can't understand why the original code (without propagation) doesn't work, and if that's by design then I guess the docs can be improved by mentioning that propagation must be used for these scenarios, so I'm leaving this issue open for now.

Thanks for the excellent project!

All 2 comments

After looking through the examples, the accordions one seems to use nesting with an AnimatePresence, but it is utilizing propagation. So I adjusted my code to do the same and it worked:

import React from "react";
import { AnimatePresence, motion } from "framer-motion";

export default function({ children, isOpen, onClose }) {
  const backdropVariants = {
    open: {
      opacity: 1
    },
    closed: {
      opacity: 0
    }
  };
  const modalVariants = {
    open: {
      translateY: 0
    },
    closed: {
      translateY: -60
    }
  };

  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          key="backdrop"
          className="backdrop"
          initial={"closed"}
          animate={isOpen ? "open" : "closed"}
          exit={"closed"}
          variants={backdropVariants}
        >
          <motion.div key="modal" className="modal" variants={modalVariants}>
            <div>{children}</div>
            <button onClick={onClose}>Close</button>
          </motion.div>
        </motion.div>
      )}
    </AnimatePresence>
  );
}

Here's the modified sandbox: https://codesandbox.io/s/hardcore-stonebraker-8zsd7

But I can't understand why the original code (without propagation) doesn't work, and if that's by design then I guess the docs can be improved by mentioning that propagation must be used for these scenarios, so I'm leaving this issue open for now.

Thanks for the excellent project!

Is there any progress on this?

Was this page helpful?
0 / 5 - 0 ratings