Skip to content

[BUG] Updating custom prop on a stable key causes unwanted variants re-evaluation and style bleeding #3545

@xellanix

Description

@xellanix

Note

Motion for Vue issues: Please open in the Motion for Vue repo.

1. Read the FAQs 👇

2. Describe the bug

When using AnimatePresence, updating the custom prop on a component while keeping the same key causes an unwanted style update/merge.

Instead of ignoring the custom prop change (since the component is technically the same and hasn't re-mounted), Framer Motion attempts to apply the variant associated with the new custom value. This results in the new styles being applied while the previous variant's styles are not correctly cleaned up, leading to a corrupted UI state (style bleeding).

3. IMPORTANT: Provide a CodeSandbox reproduction of the bug

https://codesandbox.io/p/sandbox/unexited-animatepresence-child-forked-5vy49s

4. Steps to reproduce

Steps to reproduce the behavior:

  1. Open the provided CodeSandbox link.
  2. Click the "Move" button once to advance to "Current Index: 1".
    • Note: In this reproduction, Index 0 and Index 1 share the exact same key, but have different custom values which drive different dynamic variants.
  3. Observe the "Current Style" log text below the button.
  4. See error: The log shows that the styles from the previous custom value (Index 0) persist and are merged with the styles of the new custom value (Index 1), creating an incorrect visual state.

5. Expected behavior

Changes to the custom prop while the key remains the same should be ignored regarding variant selection/animation.

The component should not re-animate or apply new variant values based on the updated custom prop while it is mounted. It should maintain the state established upon mounting (or the last successful key change). A change in custom without a change in key should not trigger a visual update or style recalculation.

6. Video or screenshots

N/A

7. Environment details

CodeSandbox & Local Environment:

  • React: 18.2.0 (Sandbox) / 19.2.3 (Local)
  • Motion: 12.34.0-alpha.0 (Both)
  • Browser: Zen (Firefox based) & Microsoft Edge
  • OS: Windows 11

FAQs

React Server Components "use client" error

If you're importing motion or m into a React Server Component environment, ensure you're importing from motion/react-client instead of motion/react.

import * as motion from "motion/react-client"
import * as m from "framer-motion/react-m"

Motion for React won't install

Different versions of Motion for React are compatible with different versions of React.

React 19: framer-motion@12.0.0-alpha.0 or higher
React 18: framer-motion@7.0.0 to framer-motion@11.x, or motion
React 17: framer-motion@6.x or lower

height: "auto" is jumping

Animating to/from auto requires measuring the DOM. There's no perfect way to do this and if you have also applied padding to the same element, these measurements might be wrong.

The recommended solution is to move padding to a child element. See this issue for the full discussion.

Preact isn't working

Motion for React isn't compatible with Preact.

AnimatePresence isn't working

Have all of its immediate children got a unique key prop that remains the same for that component every render?

// Bad: The index could be given to a different component if the order of items changes
<AnimatePresence>
    {items.map((item, index) => (
        <Component key={index} />
    ))}
</AnimatePresence>
// Good: The item ID is unique to each component
<AnimatePresence>
    {items.map((item, index) => (
        <Component key={item.id} />
    ))}
</AnimatePresence>

Is the AnimatePresence correctly outside of the controlling conditional? AnimatePresence must be rendered whenever you expect an exit animation to run - it can't do so if it's unmounted!

// Bad: AnimatePresence is unmounted - exit animations won't run
{
    isVisible && (
        <AnimatePresence>
            <Component />
        </AnimatePresence>
    )
}
// Good: Only the children are unmounted - exit animations will run
<AnimatePresence>{isVisible && <Component />}</AnimatePresence>

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions