motion icon indicating copy to clipboard operation
motion copied to clipboard

[BUG] AnimatePresence won't remove modal if a child animation has a defined exit or similar values

Open iszard opened this issue 1 year ago • 1 comments

Setup a Modal within a component that is added to the DOM through a state value.

      <AnimatePresence exitBeforeEnter={true}>
        {isCreatingNewChallenge && <NewChallenge onDone={handleDone} />}
      </AnimatePresence>

The child with a staggered animation looks like.

            <motion.li
              variants={{
                hidden: { opacity: 0, scale: 0.5 },
                visible: { opacity: 1, scale: 1 },
              }}
              // initial={{ opacity: 0, scale: 0.5 }}
              // animate={{ opacity: 1, scale: 1 }}
              exit={{ opacity: 1, scale: 1 }}
              transition={{ type: "spring", stiffness: 260 }}
              key={image.alt}
              onClick={() => handleSelectImage(image)}
              className={selectedImage === image ? "selected" : undefined}
            >
              <img {...image} />
            </motion.li>

When I comment out the exit prop. The modal will close properly but with an added delay due to the child's exit animation. Looking to set the exit value to prevent a lengthy delay while waiting for this child animation to end.

The following sand box will show that you can open the modal by clicking the add challenge button. Then close or click outside the modal. The modal will animate out but will not be removed ie, backdrop will remain.

sandbox: https://codesandbox.io/p/sandbox/r4vftd

iszard avatar Feb 20 '25 21:02 iszard

I think it has something to do with the variants and initial and animate being commented out. Because it seems to work when I use it like this:

<motion.li
    // variants={{
      //hidden: { opacity: 0, scale: 0.5 },
      //visible: { opacity: 1, scale: 1 },
    //}}
    initial={{ opacity: 0, scale: 0.5 }}
    animate={{ opacity: 1, scale: 1 }}
    exit={{ opacity: 1, scale: 1 }} // <----  offending line
    transition={{ type: "spring", stiffness: 260 }}
    key={image.alt}
    onClick={() => handleSelectImage(image)}
    className={selectedImage === image ? "selected" : undefined}
    >

or as this

<motion.li
    variants={{
      hidden: { opacity: 0, scale: 0.5 },
      visible: { opacity: 1, scale: 1 },
    }}
    initial="hidden"
    animate="visible"
    exit="visible" // <----  offending line
    transition={{ type: "spring", stiffness: 260 }}
    key={image.alt}
    onClick={() => handleSelectImage(image)}
    className={selectedImage === image ? "selected" : undefined}
    >

https://codesandbox.io/p/devbox/prod-darkness-forked-3y6gdl

bosbode avatar Mar 25 '25 16:03 bosbode