Mobile phones now account for over 55 per cent of the world’s web traffic. With this reality, responsive navigation has become a critical part of modern websites. In this tutorial, you'll learn how to build a responsive hamburger (navigation) menu in ReactJS.
The content that follows was written with new React developers in mind, therefore, experienced developers may not find the content very useful. Furthermore, this tutorial only covers navigation in ReactJS, it'll not teach you how to build navigation menus in vanilla JavaScript.
Table of contents
What you are building
Prerequisites
Tools needed
Setting things up
Steps to build a responsive navigation menu in React
Tidying up
Conclusion
What you are building
The following is what the final project will look like. You can switch things up in your project to make it look different, but the functionality will be the same.
Prerequisites
To follow along with this tutorial, you should have a basic understanding of the following:
Props and state in React
CSS media query
The command line
Tools needed
In addition to the prerequisite knowledge required, you also need the following tools:
A new or existing React app
A code editor
A web browser
You'll create a new React app in the next section if you don't have one already. While it's safe to assume you already have a web browser, you can download Google Chrome for desktops if you don't. Visual Studio Code is the code editor used here, but any other editor works fine.
Setting things up
This section will help you set things up. If you already have a React app, skip the first two steps below.
Create a React app
Confirm if NodeJS is installed on your device by running the command:
node -v
from your terminal. If a version number is returned, you are good. Otherwise, download and install NodeJS first before continuing. Once the installation is complete, create a new React application by running the following command:npx create-react-app myapp // myapp above is the name of your project
Open the project folder
Within your command line, navigate to your project's folder:
cd myapp
Start the app
Run the following command to start your new or existing app:npm start
Install packages
For this project, you need the following packages:
React-icons: This package lets you use custom-made icons in your project. To install react-icons, run the command below:
npm install react-icons //ensure you're inside your project directory:
Clear irrelevant files
Now you are all set, it's time to start building your hamburger menu project.
Steps to build a responsive hamburger Menu in React
The following steps will guide you on how to build a responsive hamburger menu in React. Unless explicitly stated, the terms: file and component refer to the same idea in this section.
Step 1: Create a new folder
Follow the steps below to create a parent folder for the entire project:
Open the project folder in a code editor
Locate the src folder
Create a new folder named Components
Step 2: Create a subfolder
Within the Components folder, create another new folder named NavBar. It's a parent folder that'll hold files relevant to your hamburger menu.
Step 3: Create components
Within the NavBar folder, create the following components:
NavBar.css
Create a new file named NavBar.css. It'll be a container for the navigation menu styles.
NavLinks
Create another new file named NavLinks.js and import the NavBar.css file you created earlier into it. For now, this component will be a stateless function component that only returns an unordered list of the items. The content of the unordered list should be what you intend to have in your navigation menu:
//NavLinks.js import './NavBar.css'; const NavLinks = () =>{ return( <nav className="NavLinks"> <ul> <li> <a href="/">Home</a> </li> <li> <a href="/#services">Services</a> </li> <li> <a href="/#about">About Us</a> </li> <li> <a href="/#contact">Contact Us</a> </li> </ul> </nav> ) } export default NavLinks; //You'll style this component by targetting the NavLinks classname above
DesktopNavigation
Create a new file and save it as DesktopNavigation.js. It'll also be a stateless function component with the following content:
//DesktopNavigation.js import NavLinks from "./NavLinks"; import './NavBar.css'; const DesktopNavigation = () =>{ return() } export default DesktopNavigation; // Note that NavBar.css and NavLinks.js are imported here
In the return block of this component, do the following:
Add a
h2
element that'll render the text "Logo" to the browser. Thish2
element, with a class name of "logo," will serve as the logo for this project:<h2 className="logo">Logo</h2>
Render the NavLinks component you imported:
<NavLinks />
Wrap both imports above in a
nav
tag and add a class name of DesktopNavigation to the tag:<nav className="DesktopNavigation"> <h2 className="logo">Logo</h2> <NavLinks /> </nav>
The final code for the DesktopNavigation component should look like this:
//DesktopNavigation.js import NavLinks from "./NavLinks"; import './NavBar.css'; const DesktopNavigation = () =>{ return( <nav className="DesktopNavigation"> <h2 className="logo">Logo</h2> <NavLinks /> </nav> ) } export default DesktopNavigation;
NavBar
Create a new file named NavBar.js:
//NavBar.js const NavBar = () => { return() } export default NavBar; //leave the return block empty for now
Step 4: Import DesktopNavigation
In the NavBar.js file you just created, import and render the DesktopNavigation component:
//NavBar.js
import DesktopNavigation from './DesktopNavigation';
const NavBar = () => {
return(
<div>
<DesktopNavigation />
</div>
)
}
export default NavBar;
Step 5: Render to the browser
Go to the App.js file and import the Navbar component:
//App.js
import NavBar from './../Components/NavBar/NavBar';
//The import statement above is different from other imports
//you have done so far because App.js lives outside
//the NavBar container you created for this navigation menu.
Next, render the imported Navbar component within the return block of your App.js file:
//App.js
import NavBar from './../Components/NavBar/NavBar';
function App() {
return (
<NavBar />
);
}
export default App;
An unstyled navigation menu should now be visible in your browser. You'll add styling to it in the next step.
Step 6: Style the navigation menu
To style the navigation menu, you'll copy style rules from this section and paste them into your NavBar.css file. But before that, locate the index.css file in the file tree and paste the following into it:
/*Index.css*/
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
/* This ensures that default browser styling doesn't affect your app
Next, fill up the content of your NavBar.css with the following:
/*NavBar.css*/
nav{
display: flex;
align-items: center;
justify-content: space-evenly;
background: aqua;
padding: 30px 50px 30px 50px;
}
.NavLinks{
height: 15vh;
}
nav ul{
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
nav ul li{
list-style-type: none;
display: inline-block;
padding: 10px 20px;
}
nav ul li a{
text-decoration: none;
font-weight: bold;
color: black;
}
nav ul li a:hover{
color: white;
transition: .3s;
}
/*You can style yours differently
That settles the styling for your navigation menu. Check the browser to ensure you have something close to the image below:
Step 7: Add a Mobile Navigation Component
Until now, you've been working on a menu for desktop and large-screen devices. It's now time to set up a separate menu for mobile devices. To do that, follow the steps below:
Create a new file and save it as MobileNavigation.js.
Copy the content of DesktopNavigation.js and paste it into this new MobileNavigation component.
Replace every instance of "DesktopNavigation" with "MobileNavigation" in the code you copied:
Step 8: Render the MobileNavigation component
Within the NavBar component, import and render MobileNavigation:
//NavBar.js
import DesktopNavigation from './DesktopNavigation';
import MobileNavigation from './MobileNavigation';
const NavBar = () => {
return(
<div>
<DesktopNavigation />
<MobileNavigation />
</div>
)
}
export default NavBar;
Because you returned both DesktopNavigation and MobileNavigation in the NavBar component above, you should be seeing duplicate navigation menus in the browser:
Ideally, you only want to render one of either DesktopNavigation or MobileNavigation (depending on the user's device) - not the two at once. You'll fix this with CSS next.
Step 9: Fix the duplicate navigation menu
In the NavBar.css file, grab the MobileNavigation classname and assign a display
value of none
to it:
/*NavBar.css*/
.MobileNavigation{
display: none;
}
/*This takes the MobileNavigation component away from the browser.
Step 10: Make the navigation menu responsive
Ideally, you want to render the MobileNavigation component (which is currently invisible) to users with small-screen devices. To implement that, go to your NavBar.css and introduce a media query:
/*NavBar.css*/
@media (max-width: 600px){
.DesktopNavigation{
display: none;
}
.MobileNavigation{
display: flex;
align-items: center;
height: 15vh;
background-color: red;
}
.NavLinks{
background-color: red;
}
}
/*the height property within this media query should be equal to the height
of the NavLinks classname
For devices with a screen width of 600px and below, the media query above does the following:
Renders the MobileNavigation component
Hides the DesktopNavigation component
Resize your browser to confirm that it's active (the background color should change to red at the 600px breakpoint). You'll replace this color change effect with a hamburger icon in the next step.
Step 11: Add a hamburger icon
Remember the react-icons
package you installed at the beginning of this tutorial? It's finally time to make use of it. The steps below explain how:
Visit the react-icons website
Enter the term "menu" into the search bar
Scan the page to identify any hamburger icon you like
Click on an icon to copy its name to your clipboard
Go to your MobileNavigation component and import the icon using the syntax below:
//MobileNavigation.js import {MdOutlineMenu} from 'react-icons/md' /*Append the first two letters of an icon's name to the end of the import statement. The letters "md" was added to 'react-icons/' because we imported 'MdOutlineMenu'
Create a variable named Hamburger and embed the imported icon within this new variable. Customize the icon with properties such as
className
,size
, andcolor
://MobileNavigation.js const Hamburger = <MdOutlineMenu className="HamburgerMenu" size="30px" color="black"/>
Lastly, render the Hamburger variable within the return statement of the MobileNavigation component:
//MobileNavigation.js import NavLinks from "./NavLinks"; import './NavBar.css'; import {MdOutlineMenu} from 'react-icons/md'; const Hamburger = <MdOutlineMenu className="HamburgerMenu" size="30px" color="black"/> const MobileNavigation = () =>{ return( <nav className="MobileNavigation"> <h2 className="logo">Logo</h2> {Hamburger} <NavLinks /> </nav> ) } export default MobileNavigation;
Step 12: Position the Hamburger Icon
You need to position the hamburger (or menu) icon to the extreme right of the browser. To implement that, locate the media query block in NavBar.css, and assign the following properties to the HamburgerMenu class name (assigned in step 11):
/*index.css*/
.HamburgerMenu{
position: absolute;
right: 2%;
cursor: pointer;
}
/*This code block should be located within your media query.
You should have a nice-looking hamburger icon rendered to your browser:
Step 13: Make the hamburger icon functional
For the hamburger icon to be functional, you'll attach an event listener to the icon. This event listener will call a function (that you'll create shortly) each time a user clicks on the icon. For now, log "click" to the console:
//MobileNavigation.js
const Hamburger = <MdOutlineMenu className="HamburgerMenu"
size="30px"
color="black"
onClick={() => console.log("click")} />
Confirm that the onClick
event is functional by checking the browser’s console for the value you logged:
Logging a value to the console is cool, but the goal is to toggle the navigation menu on/off with each click on the icon. To implement that, import the useState
hook into your MobileNavigation component:
//MobileNavigation.js
import { useState } from "react";
With the useState
hook imported, it's time to define a state and apply it in the JSX of the MobileNavigation component. The following steps will guide you:
Define a state in the MobileNavigation component:
//MobileNavigation.js const [click, setclick] = useState(false); //the state above is initialized to "false"
Within the
onClick
event, callsetClick
and pass "!click" to it as an argument. The idea is to usesetClick
to flip the state's value each time a user clicks on the hamburger icon://MobileNavigation.js const Hamburger = <MdOutlineMenu className="HamburgerMenu" size="30px" color="black" onClick={() => setclick(!click)} /> /* 1. The console.log you had before has been replaced with the state setter function (i.e setClick) 2. The exclamation mark in setClick's argument above is responsible for toggling the state's value between true/false.
Specify a condition that will determine what to display and in what circumstance. You want React to display the NavLinks component (which contains the menu items) if the state’s value is
true
and to display nothing otherwise://MobileNavigation.js <nav className="MobileNavigation"> <h2 className="logo">Logo</h2> {Hamburger} {click && <NavLinks />} // pay attention to this line </nav>
For now, your MobileNavigation component should look like this:
At this point, your hamburger icon now toggles the navigation menu on and off when clicked.
Step 14: Add a "close" icon to MobileNavigation
In mobile view, users need a way of closing the menu items displayed by clicking the hamburger icon. To implement that, follow the steps below:
Revisit the react-icons website
Search for the term "close"
Identify your preferred icon and click on it to copy its name
Import the icon to your MobileNavigation component, just like you did with the hamburger icon:
//MobileNavigation.js import {MdClose} from 'react-icons/md'; //append 'md' to 'react-icons'
Below the Hamburger variable, create a new variable named Close
Copy Hamburger's content and paste it into the new variable
Edit the code by replacing MdOutlineMenu with MdClose:
//MobileNavigation.js const Close = <MdClose className="HamburgerMenu" size="30px" color="black" onClick={() => setclick(!click)} />
Finally, in the JSX, use a ternary operator to conditionally render either the Hamburger or Close icon:
//MobileNavigation.js return( <nav className="MobileNavigation"> <h2 className="logo">Logo</h2> { click ? Close : Hamburger} {click && <NavLinks }/>} </nav> )
For clarity, your MobileNavigation component should look like this:
//MobileNavigation.js
import NavLinks from "./NavLinks";
import './NavBar.css';
import {MdOutlineMenu} from 'react-icons/md'
import { useState } from "react";
import {MdClose} from 'react-icons/md';
const MobileNavigation = () =>{
const [click, setclick] = useState(false);
const Hamburger = <MdOutlineMenu className="HamburgerMenu"
size="30px" color="black"
onClick={() => setclick(!click)} />
const Close = <MdClose className="HamburgerMenu"
size="30px" color="black"
onClick={() => setclick(!click)} />
return(
<nav className="MobileNavigation">
<h2 className="logo">Logo</h2>
{ click ? Close : Hamburger}
{click && <NavLinks />}
</nav>
)
}
export default MobileNavigation;
Step 15: Style the mobile navigation
You now have a functional navigation menu, but it doesn't behave like the typical menu you're used to. To fix that, go to the media query in your NavBar.css file and do the following:
Remove the
background-color
you assigned to the MobileNavigation and NavLinks className.Assign the following properties to the
ul
:.NavLinks ul{ display: flex; flex-direction: column; justify-content: space-evenly; position: absolute; border-top: 3px solid orange; top: 15vh; right: 0; height: 50vh; width: 100%; background:blue; }
Ensure that the value of
top
above is the same as theheight
value you assigned to the NavLinks class name in Step 6. That way, your mobile menu renders just below the navigation bar. See it in action below:
Tidying up
The project is almost complete, but there is one issue. The navigation menu does not go away when you select any of its items. To fix that, go through the steps below:
Under the Close variable ( in the MobileNavigation component), define a function called "closeMenu." When called, this function will set the state's value to
false
.const closeMenu = () => setclick(false); /* 1. The mobile navigation menu will go away when the state’s value is false. 2. You need a way to trigger this closeMenu function when a navigation item is selected.
Down in the JSX, pass props to NavLinks:
{click && <NavLinks isClicked={true} closeMenu={closeMenu}/>}
Go to the NavLinks component and receive the props:
const NavLinks = ({isClicked, closeMenu}) => { return ( <nav className="NavLinks"> <nav/> )
Still within NavLinks, attach an
onClick
event to each of the list items and pass in both isCLicked and closeMenu props:```javascript import './Navigation.css';
const NavLinks = ({isClicked, closeMenu}) => { return (
- isClicked && closeMenu()}> HOME
- isClicked && closeMenu()}> SERVICES
- isClicked && closeMenu()}> ABOUT
- isClicked && closeMenu()}> CONTACT
export default NavLinks; ```
If you made it this far, congratulations on successfully building a fully responsive hamburger menu in React!
Conclusion
This tutorial walked you through building a responsive hamburger menu in ReactJS. It may not be the only approach to navigation menus, but it's a good starting point for you as a beginner.
If you already know how to build responsive navigation menus with vanilla JavaScript, you should now compare that with what you saw in this React tutorial for a deeper level of understanding. In conclusion, adding responsive navigation to your projects is a practice you must embrace as a developer.