The React.js framework makes it possible to create single-page applications without reloading the page when visiting different links. As you move from one link to another, the change is so rapid that it is difficult to tell if the content has actually changed. Thus, we can implement transition behavior while navigating through different links or routes on a website. This improves the User Experience of the application. In this article, we will be using the Framer motion package to create page transitions.
Approach: We’ll create a portfolio application for neveropen. We will create a Navbar component. With the Navbar component, we can navigate to different components, such as Home, About, and Contact. We will use framer motion to add page transitions to different routes in our React application.
Follow the steps below and get started.
Step 1: Create React application
Make a project directory, head over to the terminal, and create a React app named “portfolio” using the following command:
npx create-react-app portfolio
After the portfolio app is created, switch to the new folder portfolio using the following command:
cd portfolio
Step 2: The Directory structure currently looks like this:
Step 3: Install the required packages.
- react-router-dom (v5): for routing
- framer-motion: for creating page transitions
Install the following dependencies by using the following command:
npm i react-router-dom framer-motion
Step 4: Add code to your index.html file.
Include the following code in your index.html file, located in the public folder of your project directory. We will use bootstrap to build our Navbar component. Import the bootstrap CDN into your index.html as follows:
Links: Put the following code at the end of the body.
<script src=”https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js” integrity=”sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p” crossorigin=”anonymous”></script>
Links: Put the following code at the end of the head:
<link rel=”stylesheet” href=”https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css” integrity=”sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm” crossorigin=”anonymous”>
index.html: Add the following code to the index.html file:
HTML
<!DOCTYPE html> < html lang = "en" > < head > < meta charset = "utf-8" /> < link rel = "icon" href = "%PUBLIC_URL%/favicon.ico" /> < meta name = "viewport" content = "width=device-width, initial-scale=1" /> < meta name = "theme-color" content = "#000000" /> < meta name = "description" content = "Web site created using create-react-app" /> < link rel = "apple-touch-icon" href = "%PUBLIC_URL%/logo192.png" /> < link href = rel = "stylesheet" integrity = "sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin = "anonymous" > < title >React App</ title > </ head > < body > < div id = "root" ></ div > < script src = integrity = "sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin = "anonymous" > </ script > </ body > </ html > |
Step 5: Creating the transitions for all the routes. We will be creating a simple fade-in and fade-out animation.
In your Src folder, create a new folder named Components. Inside the Components folder, create a new file called Transitions.js.
We will create a transition component and pass in the prop for the children, so it renders whatever is wrapped in it. When the component is mounted, we will need to wrap it in a Framer Motion component called “motion.div”.
So, we will import the motion component:
import { motion } from 'framer-motion';
We’re going to add certain props that are defined in framer motion, such as
- initial: This indicates how the component will look at the beginning of the animation.
- animate: This is what the component looks like after it has finished animating.
- exit: This defines the style of the component after it has animated out of the animation.
- transition: This specifies how long we want the duration to last.
We will configure the animation props and pass them in the variants which enable us to define the animation state.
At first, the prop is invisible. Initially, the opacity is kept at 0 to make it invisible. It will then animate for 3 seconds to become visible. This creates a simple fade-in and fade-out animation.
Transition.js: Add the following code to the Transition.js file:
Javascript
import { motion } from "framer-motion" ; const animationConfiguration = { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, }; const Transitions = ({ children }) => { return ( <motion.div variants={animationConfiguration} initial= "initial" animate= "animate" exit= "exit" transition={{ duration: 3 }} > {children} </motion.div> ); }; export default Transitions; |
Step 6: Creating the Home component for Homepage. In the Components folder, create a new file named Home.js. We will create a Home component for the homepage and wrap the component inside the Transitions Component to create a page transition.
Javascript
import React from 'react' import Transitions from './Transition' const Home = () => { return ( <> <Transitions> <h3 className= 'mt-5' style={{ color: 'green' }}> Welcome to neveropen </h3> </Transitions> </> ) } export default Home |
Step 7: Creating the About Component for the About Us page.
We will create a new file in the Components folder called About.js and then wrap the About component inside the Transitions Component to create an animation as we switch between routes. The About component consists of a brief description of neveropen.
- About Us: Add the following code in the About.js file.
Javascript
import React from 'react' import Transitions from './Transition' const About = () => { return ( <> <Transitions> <h2 className= 'mt-5 text-center' style={{ color: 'green' }}> neveropen is a computer science portal for Geeks. </h2> </Transitions> </> ) } export default About |
Step 8: Creating the Contact component for Contact Us page.
We will create a new file in the Components folder called Contact.js and then wrap the About component inside the Transitions Component to create an animation as we switch between routes. The Contact component contains neveropen’s contact address.
- Contact Us: Add the following code to the Contact.js file.
Javascript
import React from 'react' import Transitions from './Transition' const Contact = () => { return ( <> <Transitions> <h3 className= 'mt-5' style={{ color: 'green' }}> Address : neveropen <br /> 5th & 6th Floor, Royal Kapsons, A- 118, Sector- 136, Noida, Uttar Pradesh (201305) </h3> </Transitions> </> ) } export default Contact |
Step 9: Creating the Navbar Component
Create a new file in your components folder called Navbar.js. We’ll make a Navbar using Bootstrap and add the links for Home, About Us, and Contact Us. We will import the Link from the react-router-dom package.
import {Link} from 'react-router-dom'
Javascript
import React from 'react' import { Link } from 'react-router-dom' const Navbar = () => { return ( <> <nav className= "navbar navbar-expand-lg navbar-light bg-light" > <div className= "container-fluid" > <a className= "navbar-brand" href= "/" > neveropen </a> <button className= "navbar-toggler" type= "button" data-bs-toggle= "collapse" data-bs-target= "#navbarNav" aria-controls= "navbarNav" aria-expanded= "false" aria-label= "Toggle navigation" > <span className= "navbar-toggler-icon" ></span> </button> <div className= "collapse navbar-collapse" id= "navbarNav" > <ul className= "navbar-nav" > <li className= "nav-item" > <Link className= "nav-link active" aria-current= "page" to= "/" >Home</Link> </li> <li className= "nav-item" > <Link className= "nav-link" to= "/about" > About Us </Link> </li> <li className= "nav-item" > <Link className= "nav-link" to= "/contact" > Contact Us </Link> </li> </ul> </div> </div> </nav> </> ) } export default Navbar |
Step 10: Passing the components in the root App component. In the App.js file, we will create an Animated Component.
Framer Motion consists of the AnimatePresence Component, which tracks the unmounting of components. It fires the exit props when the component unmounts. We will pass the exitBeforeEnter prop that makes sure to render one component at a time.
So, we will import AnimatePresence:
import { AnimatePresence } from 'framer-motion';
We will set up routing for all the routes using react-router-dom inside the Animated Component. So, we will import the Router, Switch and Link from the react-router-dom.
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
The animate presence will work if the child component changes. In our case, we want a transition between pages. Our switch is a child component, and we need to pass it a unique key. Since we want a transition on path change, we’ll pass the path as a key in, using the UseLocation hook.
We will pass our Navbar component and the Animated Component to the root App component.
- App.js: Add the following code in the App.js file.
Javascript
import './App.css' ; import React from "react" import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom" ; import { useLocation } from 'react-router-dom' ; import About from './Components/About' ; import Contact from './Components/Contact' ; import Home from './Components/Home' ; import Navbar from './Components/Navbar' ; import { AnimatePresence } from 'framer-motion' ; const Animated = () => { const location = useLocation(); return ( <AnimatePresence exitBeforeEnter > <Switch location={location} key={location.pathname}> <Route exact path= "/" component={Home}></Route> <Route exact path= "/about" component={About}></Route> <Route exact path= "/contact" component={Contact}></Route> </Switch> </AnimatePresence> ) } function App() { return ( <div className= "App" > <> <Router> <Navbar /> <Animated /> </Router> </> </div> ); } export default App; |
Step 11: Your index.js file should look like this. The index.js file serves as the main entry point, and inside it, the App.js file is rendered at the root ID of the DOM.
Javascript
import React from 'react' ; import ReactDOM from 'react-dom' ; import './index.css' ; import App from './App' ; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById( 'root' ) ); |
The neveropen portfolio Application is ready.
Step to run the Application: Run the application by using the following command:
npm start
Output: By default, the React project will run on port 3000. You can access it at localhost:3000 on your browser. We will observe transitions between the pages as we navigate through them.