DEV Community

Cover image for Nextjs Page Transition With Framer-Motion
Joseph42A
Joseph42A

Posted on • Edited on

Nextjs Page Transition With Framer-Motion

Creating seamless and visually engaging transitions between pages has become an integral aspect of enhancing user experience. Next.js, a popular React framework, offers a powerful combination with Framer Motion, a declarative motion library for React, to bring life to page transitions, let's get started.

Setup The Project

Create a nextjs project by running this command

npx create-next-app@latest
Enter fullscreen mode Exit fullscreen mode

This will fire the nextjs project with the latest release (in my case is version 14.1.0), feel free to set up your next project as you want, I'm going to use typescript with app router, and tailwinds for styling, clean up the root page app/page.tsx from the nextjs starter page, mine is like this

app/page.tsx

export default function Home() {
  return (
    <section className="p-4">
      <div className="container">
        <h1 className="text-2xl font-bold">Home Page</h1>
        <p className="w-1/2 font-medium py-2">
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Molestias
          natus minima exercitationem perferendis hic maxime nihil officia
          fugit, illo asperiores fugiat odit harum, dicta cumque ad atque
          assumenda! Saepe dolores repellendus animi harum ex voluptatibus
          quaerat unde obcaecati quo consequuntur sequi, autem deleniti?
          Eligendi ipsa impedit cupiditate accusantium delectus quidem.
        </p>
      </div>
    </section>
  );
}

Enter fullscreen mode Exit fullscreen mode

Also, I'm going to add two more pages with the same content to the animation to look cleaner, app/about/page.tsx and app/contact/page.tsx, and add a header component for simple navigation between the pages header.tsx and use it in the layout
header.tsx

import Link from "next/link";

export default function Header() {
  return (
    <header>
      <nav className="p-4">
        <ul className="container flex gap-8">
          <li>
            <Link href="/">Home</Link>
          </li>
          <li>
            <Link href="/about">About</Link>
          </li>
          <li>
            <Link href="/contact">Contact</Link>
          </li>
        </ul>
      </nav>
    </header>
  );
}

Enter fullscreen mode Exit fullscreen mode

Add Framer Motion

To install framer-motion simply run the command below

npm install framer-motion
Enter fullscreen mode Exit fullscreen mode

Now after installing the framer-motion we gonna create a Transition.tsx component to define our base page transition using framer-motion, hers is the code for that component

"use client";

import { motion } from "framer-motion";

export default function Transition({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <motion.div
      initial={{ y: 20, opacity: 0 }}
      animate={{ y: 0, opacity: 1 }}
      transition={{ ease: "easeInOut", duration: 0.75 }}
    >
      {children}
    </motion.div>
  );
}

Enter fullscreen mode Exit fullscreen mode

As you can see this component is a client component so we marked it as a client component using use client on top of the component declaration, basically we're using motion from framer-motion and using initial, animate, and transition props we can define the page animation.

Using Nextjs Template To Render Animation Pages

You may ask why we can't just use Layout.tsx to wrap our pages with the Transition.tsx component, Just like this

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Header from "./header";
import Transition from "./trasnition";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Page Transition",
  description: "Using framer-motion to add trasition between pages",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Header />
        <Transition>{children}</Transition>
      </body>
    </html>
  );
}

Enter fullscreen mode Exit fullscreen mode

The problem is you can only see the animation for the first render (initial load), then, if you navigate to other pages, Nextjs will not rerender those pages from the layout, so that the Transition will not render for that page, So, for that case Template.tsx comes as a handy solution, here is the definition of Template from Nextjs doc

Unlike layouts that persist across routes and maintain state, templates create a new instance for each of their children on navigation. This means that when a user navigates between routes that share a template, a new instance of the component is mounted, DOM elements are recreated, state is not preserved, and effects are re-synchronized.

Now create template.tsx under the app directory, and copy paste the code from the Transition.tsx component, and rename the component name to Template(), like below

"use client";

import { motion } from "framer-motion";

export default function Template({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      initial={{ y: 20, opacity: 0 }}
      animate={{ y: 0, opacity: 1 }}
      transition={{ ease: "easeInOut", duration: 0.75 }}
    >
      {children}
    </motion.div>
  );
}

Enter fullscreen mode Exit fullscreen mode

And here you go! we have added the page transition for the project, you can customize the transition the way you want, and have a better experience, if you have any questions feel free to ask.

Github Source Code

Top comments (14)

Collapse
 
wuyasong profile image
wuyasong

nice

Collapse
 
joseph42a profile image
Joseph42A

My plesure,

Collapse
 
lansolo99 profile image
Stéphane CHANGARNIER

Exactly what I have done in my latest project, that is reassuring 👍
I had to rely on ugly hacks to make this working properly before the Next 14 release (animatePresence + mode attr.)

Collapse
 
joseph42a profile image
Joseph42A

Exactly, we had to deal with those kinds of weird hacks, but now have such a clean way to get the animation done, All Thanks to Nextjs Team

Collapse
 
druxamb profile image
Muhammad Amoo

well documented

Collapse
 
joseph42a profile image
Joseph42A

Thanks, hope it helps

Collapse
 
abdulrahmanismailhaji profile image
Abdulrahman Ismail

well done and keep growing bro🙌🙌

Collapse
 
joseph42a profile image
Joseph42A

You're welcome!

Collapse
 
grzegorzp4tyk profile image
grzegorzp4tyk

This method doesn't cover the exit animations. I did fork your repo and the transition between routes looks like the current route is simply disappearing and then the animation of next route starts (opacity etc). Do you have any idea how to fix this issue?

Collapse
 
ceemoe_b profile image
Brandon A Calderon-Morales

This is something I just noticed while trying this. Did you end up finding a solution for this?

Collapse
 
blakeshuttle profile image
blake-shuttle

How to add page transitions when using page router?

Collapse
 
rid137 profile image
Ridwan Makinde

i have followed the tutorial closely but the transition only occur on initial page load, it does not persist on when i make subsequent navigation to different pages

Collapse
 
joseph42a profile image
Joseph42A

Did you use template.ts or layout.ts make sure to use template.ts otherwise the layout effect only appear once, for working example look at my source code here
github

Collapse
 
ivan_ivanov_a43ee621180a3 profile image
Dan Viol

Exit animation is still not working that way