Using Framer Motion to make page transitions in React
Tags: react, javascript, webdev, tutorial
Published: 2021-01-27 13:10:23

In this short tutorial, we'll be learning how we can use the `AnimatePresence` component provided by Framer Motion to create our very own page transitions when navigating between pages in React!

![Animation Example](https://dev-to-uploads.s3.amazonaws.com/i/el44fn3e1jk9aczsva18.gif)

We'll be using React Router for this example - but this same principle should work for other router implementations, too (have tested with the **Next.js** router and it worked with no issues!)

## Watch the Video Tutorial:

[![Video Tutorial](https://i.imgur.com/BxK9xNo.png)](https://codesnap.io/course/react-bites/framer-motion-page-transitions)

You can also download the source code from the link above, too!

### Installing the required packages

First of all, let's install the required packages into our React project. We'll need React Router for navigation, and Framer Motion for the transition behaviour.

```
yarn add react-router-dom framer-motion
```

### Adding a BrowserRouter to our app

Next, in the top-level component where `ReactDOM.Render` is called (for me, `index.tsx`), we'll want to wrap our app's container in an instance of `<Router>` from `react-router`.

First, we'll add the necessary imports to `index.tsx`...

```ts
import { BrowserRouter as Router } from 'react-router-dom';
```

Then, we'll wrap our top-level component in an instance of this router.

```react
ReactDOM.render(
  <React.StrictMode>
    <Router> // <-- Adding this...
      <App />
    </Router> // <-- ...and this!
  </React.StrictMode>,
  document.getElementById('root')
);
```

### Building a simple switch

Next, we'll need to make some changes to the component immediately beneath the top-level component (in our example, the `App` component).

Inside the `App` component, we'll set up a basic routing system for our app. In this example, we're only going to be navigating between two simple pages - so we just need a `<Switch>` and two `<Route>` components to get us going.

So let's import those in our `App.tsx` file first...

```ts
import { Switch, Route } from 'react-router-dom';
```

Then below, we'll return our simple switch from our `App` component. For clarity, `Page1` and `Page2` components can be any valid React component.

```jsx
const App = () => {
  return (
    <Switch>
      <Route path="/page1">
        <Page1 />
      </Route>
      <Route path="/page2">
        <Page2 />
      </Route>
    </Switch>
  );
};
```

### Adding AnimatePresence from Framer Motion

Now, it's time to add the animation! First, we'll wrap our `<Switch>` in the `<AnimatePresence>` component from Framer Motion. Let's import that first...

```ts
import { AnimatePresence } from 'framer-motion';
```

Then, let's wrap our app in that new component.

```jsx
const App = () => {
  return (
    <AnimatePresence exitBeforeEnter initial={false}>
      <Switch>
        <Route path="/page1">
          <Page1 />
        </Route>
        <Route path="/page2">
          <Page2 />
        </Route>
      </Switch>
    </AnimatePresence>
  );
};
```

Transitions with `AnimatePresence` only work when the child immediately below the `AnimatePresence` component changes. In that case, that's our `Switch` component. We'll need to add some props to help `AnimatePresence` recognise when that change has occurred.

Once again, in `App.tsx`, we're going to import the `useLocation` hook from `react-router`.

```ts
import { useLocation } from 'react-router-dom';
```

And now, let's add the `location` and `key` props to our `Switch`.

```jsx
const App = () => {
  const location = useLocation();
  return (
    <AnimatePresence exitBeforeEnter initial={false}>
      <Switch location={location} key={location.pathname}>
        <Route path="/page1">
          <Page1 />
        </Route>
        <Route path="/page2">
          <Page2 />
        </Route>
      </Switch>
    </AnimatePresence>
  );
};
```

### Adding the transition effect parameters to our page components

Great news - we're done with our App component. Now, let's add some animations to our pages, and we should be ready to go!

Here's the `Page1` component I'm working with. It's super simple - just a simple `div` with some styles, and a `Link` to our other page in the app.

```jsx
const Page1 = () => {
  return (
    <div style={{ ...styles.page, ...styles.page1 }}>
      <p style={styles.copy}>This is page 1</p>
      <Link style={{ ...styles.copy, ...styles.link }} to="/page2">
        Go to Page 2
      </Link>
    </div>
  );
};
```

To trigger an animation when this `Page1` component is mounted, we'll need to wrap it in a special component called `motion.div` which is provided by Framer Motion. So, let's import that...

```ts
import { motion } from 'framer-motion';
```

Now, we'll wrap our `Page1` component in our new `motion.div` component, and provide some props to perform the animation when it's mounted.

```jsx
const Page1 = () => {
  return (
    <motion.div
      initial={{ scaleY: 0 }}
      animate={{ scaleY: 1 }}
      exit={{ scaleY: 0 }}
      transition={{ duration: 0.5 }}
    >
      <div style={{ ...styles.page, ...styles.page1 }}>
        <p style={styles.copy}>This is page 1</p>
        <Link style={{ ...styles.copy, ...styles.link }} to="/page2">
          Go to Page 2
        </Link>
      </div>
    </motion.div>
  );
};
```

As you can see, we've added three new props to our `motion.div` component here, too.

- **initial** - This is the style of the component at the **beginning** of the animation when it is **animating in**.
- **animate** - This is the style of the component at the **end** of the animation when it is **animating in**.
- **exit** - This is the style of the component at the **end** of the animation when it is **animating out**.
- **transition** - Transition configuration. Here, we're specifying how long we want the duration to last for (in our case, 0.5 seconds).

With those props in place, we can expect the following behaviour:

- When the prop is first mounted, it is invisible (`scaleY: 0`)
- Then, it will immediately animate over 0.5 seconds to be visible (`scaleY: 1`).
- When it is animating out, it will resize back down before it is removed from the DOM (`scaleY: 0`).

Finally, the only other thing we need to do is wrap our other page components that we wish to animate using the same method.

I'm animating between two pages (`Page1` and `Page2` in this example), so I'll need to wrap `Page2` in a `motion.div` tag, too.

```jsx
const Page2 = () => {
  return (
    <motion.div
      initial={{ scaleY: 0 }}
      animate={{ scaleY: 1 }}
      exit={{ scaleY: 0 }}
      transition={{ duration: 0.5 }}
    >
      <div style={{ ...styles.page, ...styles.page2 }}>
        <p style={styles.copy}>This is page 2</p>
        <Link style={{ ...styles.copy, ...styles.link }} to="/page1">
          Go to Page 1
        </Link>
      </div>
    </motion.div>
  );
};
```

### And we're done!

And with that, we are done! We have successfully set up a fancy animation when navigating between pages in React.

You should now also have all the knowledge you need to customise your transition styles, too. Each page can also have different transition styles - the sky's the limit!

### CodeSnap

[![CodeSnap Preview](https://i.imgur.com/mwdAzpU.png)](https://codesnap.io)

If you enjoyed this course, I'm uploading tutorial videos, courses, articles and plenty more. If you'd like to see more of this content, please consider signing up for the mailing list over on [**CodeSnap.io**](https://codesnap.io). It encourages me to make more videos and articles just like this one 🙏

Thanks for reading!