I’ve set up global page transitions using Framer Motion’s AnimatePresence.
Here is a semi-working demo:
Here is my code:
"use client";
import { motion, AnimatePresence } from "framer-motion";
import '@/styles/globals.css';
import { PlasmicRootProvider } from "@plasmicapp/react-web";
import type { AppProps } from "next/app";
import Head from "next/head";
import { NextUIProvider } from "@nextui-org/react";
import { useRouter } from "next/router";
import Navbar from "../components/Navbar";
import { useLayoutEffect, useEffect, useState } from "react";
export default function MyApp({ Component, pageProps }: AppProps) {
const router = useRouter();
const [scrollPosition, setScrollPosition] = useState(0);
useLayoutEffect(() => {
document.body.style.height = "100%";
document.body.style.overflow = "hidden";
return () => {
document.body.style.height = "";
document.body.style.overflow = "";
};
}, []);
useEffect(() => {
const handleRouteChangeStart = () => {
setScrollPosition(window.scrollY);
};
const handleRouteChangeComplete = () => {
window.scrollTo(0, scrollPosition);
};
router.events.on("routeChangeStart", handleRouteChangeStart);
router.events.on("routeChangeComplete", handleRouteChangeComplete);
return () => {
router.events.off("routeChangeStart", handleRouteChangeStart);
router.events.off("routeChangeComplete", handleRouteChangeComplete);
};
}, [router.events, scrollPosition]);
return (
<>
<Head>
<link rel="stylesheet" href="/output.css" />
</Head>
<PlasmicRootProvider Head={Head}>
<NextUIProvider>
<>
<Navbar />
<AnimatePresence mode="wait" initial={false}>
<motion.div
key={router.route}
initial={{ y: 50, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: -50, opacity: 0 }}
transition={{ ease: "easeInOut", duration: 0.75 }}
>
<Component {...pageProps} />
</motion.div>
</AnimatePresence>
</>
</NextUIProvider>
</PlasmicRootProvider>
</>
);
}
Now, I’ve tried everything to achieve my desired behaviour but unfortunately I can’t get there. Ideally, of course, I want Page A to keep its position as it transitions to page B (I’ve achieved this) but the side effect of having achieved that is it now assumes the same position on page B.
I want page A to maintain its position while either transitioning to the top or the relevant anchor of page B.
Bonus Question:
You’ll see I used my plasmic navbar component inside , so as to exclude it from page animations. This presents two issues. 1) I now have a navbar in studio. 2) I’m unsure how to expose the current page URL to the navbar component to achieve the “current page” effect you can see with the blue line in the video.
Am I doing all of the above at the wrong place in my heirarchy?