diff --git a/CHANGELOG.md b/CHANGELOG.md index 1448129559..25b889718c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ Motion adheres to [Semantic Versioning](http://semver.org/). Undocumented APIs should be considered internal and may change without warning. +## [Unreleased] + +### Fixed + +- `AnimatePresence`: Fix object-form `initial` values not applied on re-entry after exit completes. + ## [12.38.0] 2026-03-16 ### Added diff --git a/packages/framer-motion/src/components/AnimatePresence/__tests__/AnimatePresence.test.tsx b/packages/framer-motion/src/components/AnimatePresence/__tests__/AnimatePresence.test.tsx index cfeda6a164..29a357b154 100644 --- a/packages/framer-motion/src/components/AnimatePresence/__tests__/AnimatePresence.test.tsx +++ b/packages/framer-motion/src/components/AnimatePresence/__tests__/AnimatePresence.test.tsx @@ -1502,6 +1502,72 @@ describe("AnimatePresence with custom components", () => { expect(enterCustomValues).toContain(1) }) + test("Re-entering child with object-form initial resets to initial values when exit was complete", async () => { + const opacity = motionValue(1) + const opacityChanges: number[] = [] + + opacity.on("change", (v) => { + opacityChanges.push(v) + }) + + const Component = ({ + showA, + showB, + }: { + showA: boolean + showB: boolean + }) => { + return ( + + {showA && ( + + )} + {showB && ( + + )} + + ) + } + + const { rerender } = render() + await act(async () => { + await nextFrame() + }) + + await act(async () => { + rerender() + }) + await act(async () => { + await nextFrame() + }) + + expect(opacity.get()).toBe(0) + + opacityChanges.length = 0 + await act(async () => { + rerender() + }) + await act(async () => { + await nextFrame() + }) + + expect(opacityChanges.length).toBeGreaterThan(0) + expect(opacityChanges[0]).toBe(0.5) + }) + test("Does not get stuck when state changes cause rapid key alternation in mode='wait'", async () => { /** * Reproduction from #3141: A loading/loaded pattern where diff --git a/packages/framer-motion/src/motion/features/animation/exit.ts b/packages/framer-motion/src/motion/features/animation/exit.ts index 5872216ced..a5d3c8b058 100644 --- a/packages/framer-motion/src/motion/features/animation/exit.ts +++ b/packages/framer-motion/src/motion/features/animation/exit.ts @@ -25,7 +25,12 @@ export class ExitAnimationFeature extends Feature { if (this.isExitComplete) { const { initial, custom } = this.node.getProps() - if (typeof initial === "string") { + if ( + typeof initial === "string" || + (typeof initial === "object" && + initial !== null && + !Array.isArray(initial)) + ) { const resolved = resolveVariant( this.node, initial,