Full Page Transitions with Next.js
Tags: nextjs, react, animation, framer
Published: 2021-07-24 22:12:18

---

title: Full Page Transitions with Next.js

published: true
description: Create smooth full page transitions with Next.js framework and Framer Motion
tags: nextjs,reactjs,animation,framer
---

I'm going to show you how to do full page transitions with [Framer Motion](https://www.framer.com/motion/) and Next.js
Basic familiarity with Framer Motion and next.js is good to have, but the code is short and not complicated so everyone should be able to follow along.

Check out the demo: https://nextjs-full-page-transitions.netlify.app/
Fork the repository: https://github.com/ivandotv/nextjs-page-transitions

## What we are building
![slide-right](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a5xo7z1jfreiaf2n9ve8.gif)
![fade-back](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qfni3wxnmi3x4ntphron.gif)
![rotate-z](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/plwfrghfs0k98im0w1b8.gif)
   

Not only we are going to enable full page transitions but we are also going to set up a few different transitions for demo purposes.

## The code

Spoiler alert, this is all the code that is needed to enable page transitions in Next.js!

```tsx
// _app.tsx
function MyApp({ Component, pageProps, router }: AppProps) {
  return (
    <div className="app-wrap">
      <LazyMotion features={domAnimation}>
        <AnimatePresence exitBeforeEnter>
          <m.div
            key={router.route.concat(animation.name)}
            className="page-wrap"
            initial="initial"
            animate="animate"
            exit="exit"
            variants={animation.variants}
            transition={animation.transition}
          >
            <Component {...pageProps} />
          </m.div>
        </AnimatePresence>
      </LazyMotion>
    </div>
  )
}
```

Now let us go through it step by step.

First, you will notice that I'm using `LazyMotion` component, instead of regular `Motion` component, this is just for reducing the size of the bundle. Framer is not a small library
(around 25kb full), and since this code goes into the Next.js `_app` component, which is the **main** component in the framework, everything that is imported there, will be bundled in the **initial bundle download**

> When you build the project this is indicated by the `First Load JS shared by all` item in the Next.js build report.

Granted, `LazyMotion` will not slice the size of the bundle by much (around 5-7kb) but why not use it when it's available. Also, the folks that support Framer
are working on reducing the bundle size even more, so you are ready to receive more size savings in the future.

> You will notice that we are using `features={domAnimation}` on the `LazyMotion` component which means that we are only bundling a subset of Framer functionality. Things like **pan and drag gestures** and **layout animations** will not be available. Check out the [official documention](https://www.framer.com/docs/lazy-motion/) for the component to know more.

### AnimatePresence Component

`AnimatePresence` component is used for animating child components when they are **removed** from the React tree. It
allows the component to defer unmounting until after the animation is complete. The most crucial property for this component is
`exitBeforeEnter`, it allows Framer to animate one component at a time.
So the page, which is the `Component` in this whole setup, after a route change will animate **out** and then the new page (which is also a `Component`) will animate in. So there will be no **overlap** and we only get to see one page at any given time.

UPDATE:
I have updated the demo to show how transitions work when `exitBeforeEnter` is set to false. When this property is `false` it will enable animations on both pages (new and old at the same time). Make sure to enable the "overlap page transitions" checkbox.


![rotate-z](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vohtkxzgyj705te8ivju.gif)
 
![rotate-z-overlap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6pp4czozylca17vwwmgo.gif)
 
### m.div  component

`Motion` and `m` components are the main building blocks for Framer animations. Anything you want animated should go inside these components.

> `m.div` component is very similar to regular Framer `Motion` component. It is an optimized version that works in tandem with `LazyMotion`.

By default, the motion component comes pre-bundled with all of its features. The `m` component can be used in the same way as `Motion`, but it comes with no features preloaded. These are then provided by `LazyMotion`.

## Animations

Framer supports a lot of different ways to create the actual animations, in this demo we are going to use the `labels` functionality of Framer to animate the components. Take a look at this basic example, it will animate `ComponentToAnimate` **opacity** from 0 to 1 and then back to 0.

```jsx
function MyApp() {
  return (
    <m.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      transition={{ duration: 0.7 }}
    >
      <ComponentToAnimate />
    </m.div>
  )
}
```

- `initial` - How the element should look when the element is mounted into the React tree (before the animation starts)
- `animate` - How it should look when the animation ends (basically when it's animated into position)
- `exit` - How it should look when it's
 animated out (just before it's removed from the React tree )
- `transition` - how will the actual animation behave duration, easing, etc. It is similar to the `css` transitions property.

Our page animations are a little bit more complicated than that, and we are also dynamically changing animations in the demo, so we are going to add another property to the `m.div` component

- `variants` - this will allow us to organize animations as objects, and refer to them by name, and switch between them on demand.

Simple example is worth 1000 words:

```jsx
const myAnimation = {
  initial: {
    opacity: 0
  },
  animate: {
    opacity: 1
  },
  exit: {
    opacity: 0
  },
  transition: {
    duration: 0.7
  }
}

function Component() {
  return (
    <m.div
      initial="initial"
      animate="animate"
      exit="exit"
      transition={myAnimation.transition}
      variants={myAnimation}
    />
  )
}
```

So now we can easily switch animations by providing a different object to the `variants` property (myAnimation). In the demo, we are doing this via the HTML dropdown elements and simple `useState` hook. You can refer to the `animations.ts` file to see all the animations that are used in the demo

```ts
// animations.ts excerp
const slideUp = {
  name: 'Slide Up',
  variants: {
    initial: {
      opacity: 0,
      top: '100vh',
      scale: 0.4
    },
    animate: {
      opacity: 1,
      top: '0vh',
      scale: 1
    },
    exit: {
      opacity: 0,
      top: '100vh',
      scale: 0.4
    }
  },
  transition: {
    duration: 0.7
  }
}

const slideRight = {
  name: 'Slide Right',
  variants: {
    initial: {
      opacity: 0,
      left: '-100%',
      scale: 0.6
    },
    animate: {
      opacity: 1,
      left: 0,
      scale: 1
    },
    exit: {
      opacity: 0,
      left: '100%',
      scale: 0.6
    }
  },
  transition: {
    duration: 0.7
  }
}
```

And that's it. As you can see, full-page transitions in Next.js with Framer Motion library are not that complicated :)

Check out the demo: https://nextjs-full-page-transitions.netlify.app/
Fork the repository: https://github.com/ivandotv/nextjs-page-transitions