Nextjs Page Transition With Framer-Motion
Tags: typescript, nextjs, animation, webdev
Published: 2024-01-28 22:14:51

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
```
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>
  );
}

```
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>
  );
}

```

## Add Framer Motion
To install framer-motion simply run the command below

```
npm install framer-motion
```
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>
  );
}

```
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>
  );
}

```
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>
  );
}

```
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](https://github.com/Joseph42A/nextjs-page-transition-framer-motion)