motion icon indicating copy to clipboard operation
motion copied to clipboard

[BUG] `AnimatePresence` is bugging when animating with `key` change using `variants`

Open Profesor08 opened this issue 9 months ago • 3 comments

2. Describe the bug

Encoutered weird animations when trying to make an carousel using AnimatePresence and key prop. Based on this example https://motion.dev/docs/react-animate-presence#changing-key

In example everithing works fine, but it is using [email protected], not motion and not latest version. Thre is repo: https://codesandbox.io/p/sandbox/framer-motion-image-gallery-forked-dxc37r?file=%2Fsrc%2FExample.tsx%3A51%2C1

  1. Press fast multiple times ArrowLeft and then multiple times ArrowRight
  2. All works fine

Now, I'm using latest motion, repo: https://stackblitz.com/edit/vitejs-vite-rfdwfc6u?file=src%2Fmain.tsx,src%2FExample.tsx&terminal=dev

  1. Press fast multiple times ArrowLeft and then multiple times ArrowRight
  2. Animation direction is wrong
  3. Animation direction becomes normal when you press same amount of times on ArrowRight

3. IMPORTANT: Provide a CodeSandbox reproduction of the bug

https://stackblitz.com/edit/vitejs-vite-rfdwfc6u?file=src%2Fmain.tsx,src%2FExample.tsx&terminal=dev

4. Steps to reproduce

  1. Press fast multiple times ArrowLeft and then multiple times ArrowRight
  2. Animation direction is wrong
  3. Animation direction becomes normal when you press same amount of times on ArrowRight

5. Expected behavior

To see correct animations

6. Video or screenshots

https://github.com/user-attachments/assets/94704973-5359-45fa-b22e-2eb22ac1071a

Profesor08 avatar May 21 '25 12:05 Profesor08

Current workaround is to not to use variants, but to pass explicitly all cumputed props to motion component. But this is not ideal, it will have some edge cases, with this bug.

<AnimatePresence initial={false}>
  <motion.div
    className={styles.content}
    key={page}
    initial={{
      x: direction > 0 ? "100%" : "-100%",
      scale: 0.7,
      opacity: 0,
    }}
    animate={{
      zIndex: 1,
      x: 0,
      scale: 1,
      opacity: 1,
    }}
    exit={{
      zIndex: 0,
      x: direction < 0 ? "100%" : "-100%",
      scale: 0.7,
      opacity: 0,
    }}
  />
</AnimatePresence>

Profesor08 avatar May 21 '25 12:05 Profesor08

Current workaround is to not to use variants, but to pass explicitly all cumputed props to motion component. But this is not ideal, it will have some edge cases, with this bug.

0 ? "100%" : "-100%", scale: 0.7, opacity: 0, }} animate={{ zIndex: 1, x: 0, scale: 1, opacity: 1, }} exit={{ zIndex: 0, x: direction

But with this workaround, exiting slide will not track any of direction properties.

Profesor08 avatar Aug 27 '25 13:08 Profesor08

+1, I am also experiencing a similar bug. For me, when using children with the stagger effect: only components present on mount with stable key prop values will be animated - if the key for a given item (e.g. from a .map() expression) changes between the initial render and a subsequent one, then it will stay in its initial state forever.

artus9033 avatar Nov 06 '25 22:11 artus9033

+1, recently encountered the exact same bug while developing a carousel

After debugging, it was found that the root cause might be that DOM elements that should have been destroyed were not destroyed when switching images continuously to the left (while they can be destroyed normally when switching continuously or slowly), resulting in the image starting to move from an odd position the next time it appears

QiuYeDx avatar Dec 02 '25 09:12 QiuYeDx