diff --git a/dev/react/src/tests/animate-presence-pop-rtl.tsx b/dev/react/src/tests/animate-presence-pop-rtl.tsx
new file mode 100644
index 0000000000..9816f9a801
--- /dev/null
+++ b/dev/react/src/tests/animate-presence-pop-rtl.tsx
@@ -0,0 +1,47 @@
+import { AnimatePresence, motion } from "framer-motion"
+import { useState } from "react"
+
+export const App = () => {
+ const [state, setState] = useState(true)
+
+ return (
+
+
setState(!state)}
+ >
+
+
+ {state ? (
+
+ ) : null}
+
+
+
+ )
+}
diff --git a/packages/framer-motion/cypress/integration/animate-presence-pop-rtl.ts b/packages/framer-motion/cypress/integration/animate-presence-pop-rtl.ts
new file mode 100644
index 0000000000..8a47e02bb9
--- /dev/null
+++ b/packages/framer-motion/cypress/integration/animate-presence-pop-rtl.ts
@@ -0,0 +1,20 @@
+describe("AnimatePresence popLayout RTL", () => {
+ it("correctly pops exiting elements in RTL direction without shifting", () => {
+ let initialLeft: number
+
+ cy.visit("?test=animate-presence-pop-rtl")
+ .wait(50)
+ .get("#b")
+ .then(([$b]: any) => {
+ initialLeft = $b.getBoundingClientRect().left
+ })
+ .get("#container")
+ .trigger("click", 60, 60, { force: true })
+ .wait(100)
+ .get("#b")
+ .should(([$b]: any) => {
+ const bbox = $b.getBoundingClientRect()
+ expect(bbox.left).to.equal(initialLeft)
+ })
+ })
+})
diff --git a/packages/framer-motion/src/components/AnimatePresence/PopChild.tsx b/packages/framer-motion/src/components/AnimatePresence/PopChild.tsx
index 1eb727a4ff..aaf586874d 100644
--- a/packages/framer-motion/src/components/AnimatePresence/PopChild.tsx
+++ b/packages/framer-motion/src/components/AnimatePresence/PopChild.tsx
@@ -14,6 +14,7 @@ interface Size {
left: number
right: number
bottom: number
+ direction: string
}
interface Props {
@@ -54,6 +55,7 @@ class PopChildMeasure extends React.Component {
size.left = element.offsetLeft
size.right = parentWidth - size.width - size.left
size.bottom = parentHeight - size.height - size.top
+ size.direction = computedStyle.direction
}
return null
@@ -79,6 +81,7 @@ export function PopChild({ children, isPresent, anchorX, anchorY, root, pop }: P
left: 0,
right: 0,
bottom: 0,
+ direction: "ltr",
})
const { nonce } = useContext(MotionConfigContext)
/**
@@ -100,10 +103,13 @@ export function PopChild({ children, isPresent, anchorX, anchorY, root, pop }: P
* styles set via the style prop.
*/
useInsertionEffect(() => {
- const { width, height, top, left, right, bottom } = size.current
+ const { width, height, top, left, right, bottom, direction } = size.current
if (isPresent || pop === false || !ref.current || !width || !height) return
- const x = anchorX === "left" ? `left: ${left}` : `right: ${right}`
+ const isRTL = direction === "rtl"
+ const x = anchorX === "left"
+ ? (isRTL ? `right: ${right}` : `left: ${left}`)
+ : (isRTL ? `left: ${left}` : `right: ${right}`)
const y = anchorY === "bottom" ? `bottom: ${bottom}` : `top: ${top}`
ref.current.dataset.motionPopId = id