How to Create a Collapsible Navigation Menu Using React

A sidebar navigation menu typically consists of a vertical list of links. You can create a set of links in React using react-router-dom.

Follow these steps to create a React side navigation menu with links containing material UI icons. The links will render different pages when you click them.

Creating a React Application

If you already have a React project, feel free to skip to the next step.

You can use the create-react-app command to get up and running with React quickly. It installs all the dependencies and configuration for you.

Run the following command to create a React project called react-sidenav.

npx create-react-app react-sidenav

This will create a react-sidenav folder with some files to get you started. To clean up this folder a bit, navigate to the src folder and replace the contents of App.js with this:

import './App.css';

function App() {
return (
<div className="App"></div>

export default App;

Creating the Navigation Component

The navigation component you will create will look like this:

It is pretty simple, but once you’re finished, you should be able to modify it to suit your needs. You can collapse the navigation component using the double arrow icon at the top:

Start by creating the non-collapsed view. Apart from the arrow icon, the sidebar contains a list of items. Each of these items has an icon and some text. Instead of repetitively creating an element for each, you can store the data for each item in an array and then iterate over it using a map function.

To demonstrate, create a new folder called lib and add a new file called navData.js.

import HomeIcon from '@mui/icons-material/Home';
import TravelExploreIcon from '@mui/icons-material/TravelExplore';
import BarChartIcon from '@mui/icons-material/BarChart';
import SettingsIcon from '@mui/icons-material/Settings';

export const navData = [
id: 0,
icon: <HomeIcon/>,
text: "Home",
link: "/"
id: 1,
icon: <TravelExploreIcon/>,
text: "Explore",
link: "explore"
id: 2,
icon: <BarChartIcon/>,
text: "Statistics",
link: "statistics"
id: 3,
icon: <SettingsIcon/>,
text: "Settings",
link: "settings"

The icons used above are from the Material UI library, so install it first using this command:

npm install @mui/material @emotion/react @emotion/styled
npm install @mui/icons-material

Next, create a folder called Components and add a new component called Sidenav.js.

In this file, import navData from ../lib and create the skeleton for the Sidenav function:

import { navData } from "../lib/navData";
export default function Sidenav() {
return (

To create the links, modify the div element in this component to this:

<button className={styles.menuBtn}>
<KeyboardDoubleArrowLeftIcon />
{ =>{
return <div key={} className={styles.sideitem}>
<span className={styles.linkText}>{item.text}</span>

This component creates a navigation link containing the icon and the link text for each iteration in the map function.

The button element holds the left arrow icon from the Material UI library. Import it at the top of the component using this code.

import KeyboardDoubleArrowLeftIcon from '@mui/icons-material/KeyboardDoubleArrowLeft';

You might also have noticed that the class names reference a styles object. This is because this tutorial uses CSS modules. CSS modules allow you to create locally scoped styles in React. You don’t need to install or configure anything if you used create-react-app to start this project.

In the Components folder, create a new file called sidenav.module.css and add the following:

.sidenav {
width: 250px;
transition: width 0.3s ease-in-out;
height: 100vh;
background-color: rgb(10,25,41);
padding-top: 28px;

.sidenavClosed {
composes: sidenav;
transition: width 0.3s ease-in-out;
width: 60px

.sideitem {
display: flex;
align-items: center;
padding: 10px 20px;
cursor: pointer;
text-decoration: none;

.linkText {
padding-left: 16px;

.linkTextClosed {
composes: linkText;
visibility: hidden;

.sideitem:hover {

.menuBtn {
align-self: center;
align-self: flex-start;
justify-self: flex-end;
background-color: transparent;
border: none;
cursor: pointer;
padding-left: 20px;

Setting Up React Router

The div elements returned by the map function should be links. In React, you can create links and routes using react-router-dom.

In the terminal, install react-router-dom via npm.

npm install react-router-dom@latest

This command installs the latest version of react-router-dom.

In Index.js, wrap the App component with the Router.

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));

<App />

Next, in App.js, add your routes.

import {
} from "react-router-dom";

import './App.css';
import Sidenav from './Components/Sidenav';
import Explore from "./Pages/Explore";
import Home from "./Pages/Home";
import Settings from "./Pages/Settings";
import Statistics from "./Pages/Statistics";

function App() {
return (
<div className="App">
<Route path="/" element={<Home />}/>
<Route path="/explore" element={<Explore />} />
<Route path="/statistics" element={<Statistics />}/>
<Route path="/settings" element={<Settings />} />
export default App;

Modify App.css with these styles.

body {
margin: 0;
padding: 0;

.App {
display: flex;

main {
padding: 10px;

Each route returns a different page depending on the URL passed to the path props. Create a new folder called Pages and add four components — the Home, Explore, Statistics, and Settings page. Here is an example:

export default function Home() {
return (

If you visit the /home path, you should see “Home”.

The links in the sidebar should lead to the matching page when you click them. In Sidenav.js, modify the map function to use the NavLink component from react-router-dom instead of the div element.

{ => {
return <NavLink key={} className={styles.sideitem} to={}>
<span className={styles.linkText}>{item.text}</span>

Remember to import NavLink at the top of the file.

import { NavLink } from "react-router-dom";

NavLink receives the URL path for the link through the to prop.

Up to this point, the navigation bar is open. To make it collapsible, you can toggle its width by changing the CSS class when a user clicks the arrow button. You can then change the CSS class again to open it.

To achieve this toggle functionality, you need to know when the sidebar is open and closed.

For this, use the useState hook. This React hook allows you to add and track the state in a functional component.

In sideNav.js, create the hook for the open state.

const [open, setopen] = useState(true)

Initialize the open state to true, so the sidebar will always be open when you start the application.

Next, create the function that will toggle this state.

const toggleOpen = () => {

You can now use the open value to create dynamic CSS classes like this:

<div className={open?styles.sidenav:styles.sidenavClosed}>
<button className={styles.menuBtn} onClick={toggleOpen}>
{open? <KeyboardDoubleArrowLeftIcon />: <KeyboardDoubleArrowRightIcon />}
{ =>{
return <NavLink key={} className={styles.sideitem} to={}>
<span className={open?styles.linkText:styles.linkTextClosed}>{item.text}</span>

The CSS class names used will be determined by the open state. For example, if open is true, the outer div element will have a sidenav class name. Otherwise, the class will be sidenavClosed.

This is the same for the icon, which changes to the right arrow icon when you close the sidebar.

Remember to import it.

import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight';

The sidebar component is now collapsible.

Grab the complete code from this GitHub repository and try it yourself.

Styling React Components

React makes it straightforward to build a collapsible navigation component. You can use some of the tools that React provides like react-router-dom to handle routing and hooks to keep track of the collapsed state.

You can also use CSS modules to style components, although you don’t have to. Use them to create locally scoped classes that are unique and that you can shake from the bundle files if they are not in use.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button