motiondivision / motiondivision/motion

[BUG] AnimatePresence popLayout does not overlay the component in React Router 6

Open
#2,503 0 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.