motiondivision / motiondivision/motion
[BUG] AnimatePresence popLayout does not overlay the component in React Router 6
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 33.7k
- Forks
- 1.4k
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 14
Description
When using the AnimatePresence mode="popLayout" inside of a React Router 6 route, the "popped" component is inserted into that DOM as a sibling to the entering component, so the new component is not "popped" out of the page.
This may be related to the warning that appears in the dev console which may have a fix here :
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of `PopChild`.
at Routes (http://localhost:5173/node_modules/.vite/deps/chunk-WKEOGKIS.js?v=087143ff:4043:5)
at PopChildMeasure (http://localhost:5173/node_modules/.vite/deps/framer-motion.js?v=087143ff:7058:23)
at PopChild (http://localhost:5173/node_modules/.vite/deps/framer-motion.js?v=087143ff:7079:21)
at PresenceChild (http://localhost:5173/node_modules/.vite/deps/framer-motion.js?v=087143ff:7114:24)
at AnimatePresence (http://localhost:5173/node_modules/.vite/deps/framer-motion.js?v=087143ff:7180:26)
at MyRoutes (http://localhost:5173/src/MyRoutes.tsx?t=1706572828327:17:22)
at Router (http://localhost:5173/node_modules/.vite/deps/chunk-WKEOGKIS.js?v=087143ff:3986:15)
at BrowserRouter (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=087143ff:543:5)
at App
CodeSandbox is here
To reproduce, just create the following Components.
App.tsx:
import { BrowserRouter } from 'react-router-dom'
import MyRoutes from './MyRoutes';
function App() {
return (
<BrowserRouter>
<MyRoutes />
</BrowserRouter>
);
}
export default App
MyRoutes.tsx:
import { Route, Routes, useLocation } from "react-router"
import Component1 from "./Component1";
import { AnimatePresence } from "framer-motion";
import Component2 from "./Component2";
function MyRoutes() {
const location = useLocation();
return (
<AnimatePresence mode="popLayout">
<Routes location={location} key={location.pathname}>
<Route path="/first" element={<Component1 />} />
<Route path="/second" element={<Component2 />} />
</Routes>
</AnimatePresence>
);
}
export default MyRoutes;
Component1.tsx:
import { motion } from "framer-motion";
import { Link } from "react-router-dom";
function Component1() {
return (
<motion.div
initial={{ x: 100 }}
animate={{ x: 0 }}
exit={{ x: -100 }}
transition={{
duration: 2,
}}
>
<Link to="/second">First</Link>
</motion.div>
);
}
export default Component1;
Component2.tsx:
import { motion } from "framer-motion";
import { Link } from "react-router-dom";
function Component2() {
return (
<motion.div
initial={{ x: 100 }}
animate={{ x: 0 }}
exit={{ x: -100 }}
transition={{
duration: 2,
}}
>
<Link to="/first">Second</Link>
</motion.div>
);
}
export default Component2;
I would expect the exiting component to "pop out" of the layout so it doesn't effect the new component coming in.
This in a Vite + Typescript project.
Video:
https://github.com/framer/motion/assets/74564699/10936eda-fada-4bae-901c-678fcb5d4e49
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the issue with the App.tsx and MyRoutes.tsx examples using React Router 6 and AnimatePresence mode="popLayout". Start by tracing the PopChild and PopChildMeasure entries from the warning, then verify the exiting route no longer remains as a normal sibling of the entering route and that the ref warning is resolved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript, vite
- Domain
- frontend, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100