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!
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:
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
...
import { BrowserRouter as Router } from 'react-router-dom';
Then, we'll wrap our top-level component in an instance of this router.
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...
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.
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...
import { AnimatePresence } from 'framer-motion';
Then, let's wrap our app in that new component.
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
.
import { useLocation } from 'react-router-dom';
And now, let's add the location
and key
props to our Switch
.
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.
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...
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.
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.
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
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. It encourages me to make more videos and articles just like this one π
Thanks for reading!
Top comments (2)
Hey Willem!
Glad you enjoyed the guide :)
If I understand you correctly, to get your desired behaviour, it should be as straightforward as adjusting the
initial
,animate
andexit
props to fit your needs for each page separately. In the example I describe in the original post, we use the same props for both pages in order to gain the same transition when navigating through each page.However, if you wanted to adjust, say,
Page2
's transition animation in, you simply need to change the properties for thePage2
component!Here's an example. Below,
Page1
would enter with ascaleY
effect (stretching vertically), andPage2
would enter with ascaleX
effect (stretching horizontally).You're not limited to just
scaleX
orscaleY
- it can be any combination of any CSS properties! I'm just using these as a simple example.Hope that helps!
hey, please give me a full code. i am new for framer