A sidebar is an important element of a website’s design since it allows users to quickly visit any section within a site.
A glimpse of the project:
Prerequisite:
- IDE of choice (this tutorial uses VS Code, you can download it here)
- npm
- create-react-app
- react-router-dom
- useState React hooks
Basic Setup: You will start a new project using create-react-app so open your PowerShell or your IDE’s terminal and type:
Note: “react-sidebar-dropdown” is the name of your project, you can name it something else such as “my-first-react-website” but for now let’s stick with react-sidebar-dropdown
npx create-react-app react-sidebar-dropdown
Now go to your react-sidebar-dropdown folder by typing the given command in the terminal:
cd react-sidebar-dropdown
Required module: Install the dependencies required in this project by typing the given command in the terminal.
npm install react-router-dom npm install --save styled-components npm install --save react-icons
Once the packages and dependencies are finished downloading, start up your IDE and locate your project folder.
Now create the components folder in src then go to the components folder and create three files Sidebar.js, SidebarData.js, and SubMenu.js.
Create one more folder in src by the name pages and in pages create files by the name AboutUs.js, ContactUs.js, Events.js, Services.js, and Support.js.
Project Structure: The file structure in the project will look like this.
Filename- Sidebar.js: Open & Close Sidebar View, that’s where the role of the useState() hook comes into play.
We create a state with the first element sidebar as an initial state having a value of false and the second element as function setSidebar() for updating the state. Then a function is created by the name showSidebar() which sets the value of the sidebar opposite to its present value whenever it is called.
This function is used with the menu bars icon and cross icon with the help of onClick() function. When we click on the bars icon to see the sidenav links it sets the value of the state to true, displays the sidebar and a cross icon appears in place of the bars’ icon. When we want to close the sidebar we simply click on the cross icon and it gets replaced with a bar icon after closing the sidebar because now the value of the state is set to false.
Javascript
import React, { useState } from "react" ; import styled from "styled-components" ; import { Link } from "react-router-dom" ; import * as FaIcons from "react-icons/fa" ; import * as AiIcons from "react-icons/ai" ; import { SidebarData } from "./SidebarData" ; import SubMenu from "./SubMenu" ; import { IconContext } from "react-icons/lib" ; const Nav = styled.div` background: #15171c; height: 80px; display: flex; justify-content: flex-start; align-items: center; `; const NavIcon = styled(Link)` margin-left: 2rem; font-size: 2rem; height: 80px; display: flex; justify-content: flex-start; align-items: center; `; const SidebarNav = styled.nav` background: #15171c; width: 250px; height: 100vh; display: flex; justify-content: center; position: fixed; top: 0; left: ${({ sidebar }) => (sidebar ? "0" : "-100%" )}; transition: 350ms; z-index: 10; `; const SidebarWrap = styled.div` width: 100%; `; const Sidebar = () => { const [sidebar, setSidebar] = useState( false ); const showSidebar = () => setSidebar(!sidebar); return ( <> <IconContext.Provider value={{ color: "#fff" }}> <Nav> <NavIcon to= "#" > <FaIcons.FaBars onClick={showSidebar} /> </NavIcon> <h1 style={{ textAlign: "center" , marginLeft: "200px" , color: "green" }} > neveropen </h1> </Nav> <SidebarNav sidebar={sidebar}> <SidebarWrap> <NavIcon to= "#" > <AiIcons.AiOutlineClose onClick={showSidebar} /> </NavIcon> {SidebarData.map((item, index) => { return <SubMenu item={item} key={index} />; })} </SidebarWrap> </SidebarNav> </IconContext.Provider> </> ); }; export default Sidebar; |
Filename- SidebarData.js:
Javascript
import React from "react" ; import * as FaIcons from "react-icons/fa" ; import * as AiIcons from "react-icons/ai" ; import * as IoIcons from "react-icons/io" ; import * as RiIcons from "react-icons/ri" ; export const SidebarData = [ { title: "About Us" , path: "/about-us" , icon: <AiIcons.AiFillHome />, iconClosed: <RiIcons.RiArrowDownSFill />, iconOpened: <RiIcons.RiArrowUpSFill />, subNav: [ { title: "Our Aim" , path: "/about-us/aim" , icon: <IoIcons.IoIosPaper />, }, { title: "Our Vision" , path: "/about-us/vision" , icon: <IoIcons.IoIosPaper />, }, ], }, { title: "Services" , path: "/services" , icon: <IoIcons.IoIosPaper />, iconClosed: <RiIcons.RiArrowDownSFill />, iconOpened: <RiIcons.RiArrowUpSFill />, subNav: [ { title: "Service 1" , path: "/services/services1" , icon: <IoIcons.IoIosPaper />, cName: "sub-nav" , }, { title: "Service 2" , path: "/services/services2" , icon: <IoIcons.IoIosPaper />, cName: "sub-nav" , }, { title: "Service 3" , path: "/services/services3" , icon: <IoIcons.IoIosPaper />, }, ], }, { title: "Contact" , path: "/contact" , icon: <FaIcons.FaPhone />, }, { title: "Events" , path: "/events" , icon: <FaIcons.FaEnvelopeOpenText />, iconClosed: <RiIcons.RiArrowDownSFill />, iconOpened: <RiIcons.RiArrowUpSFill />, subNav: [ { title: "Event 1" , path: "/events/events1" , icon: <IoIcons.IoIosPaper />, }, { title: "Event 2" , path: "/events/events2" , icon: <IoIcons.IoIosPaper />, }, ], }, { title: "Support" , path: "/support" , icon: <IoIcons.IoMdHelpCircle />, }, ]; |
Filename- SubMenu.js: The logic for Dropdown links, again done with useState() hooks.
We create a state with the first element subnav as an initial state having a value of the false and the second element as function setSubnav() for updating the state. Then a function is created by the name showSubnav() which sets the value of subnav opposite to its present value whenever it is called.
This function is used with the open icon and close icon. When we click on the open icon to see the dropdown links it sets the value of the state to true, displays the dropdown menu and a close icon appears in place of the open icon. When we want to close the dropdown links we simply click on the close icon and it gets replaced with an open icon after closing the dropdown menu because now the value of the state is set to false.
As every sidelink is not having a dropdown menu, it first checks if a sideline has a property of subNav defined with it from the object array that we made in the SidebarData.js file. If that property exists then it executes the above logic otherwise the sidelinks appear normally without any open and close icons.
Javascript
import React, { useState } from "react" ; import { Link } from "react-router-dom" ; import styled from "styled-components" ; const SidebarLink = styled(Link)` display: flex; color: #e1e9fc; justify-content: space-between; align-items: center; padding: 20px; list-style: none; height: 60px; text-decoration: none; font-size: 18px; &:hover { background: #252831; border-left: 4px solid green; cursor: pointer; } `; const SidebarLabel = styled.span` margin-left: 16px; `; const DropdownLink = styled(Link)` background: #252831; height: 60px; padding-left: 3rem; display: flex; align-items: center; text-decoration: none; color: #f5f5f5; font-size: 18px; &:hover { background: green; cursor: pointer; } `; const SubMenu = ({ item }) => { const [subnav, setSubnav] = useState( false ); const showSubnav = () => setSubnav(!subnav); return ( <> <SidebarLink to={item.path} onClick={item.subNav && showSubnav}> <div> {item.icon} <SidebarLabel>{item.title}</SidebarLabel> </div> <div> {item.subNav && subnav ? item.iconOpened : item.subNav ? item.iconClosed : null } </div> </SidebarLink> {subnav && item.subNav.map((item, index) => { return ( <DropdownLink to={item.path} key={index}> {item.icon} <SidebarLabel>{item.title}</SidebarLabel> </DropdownLink> ); })} </> ); }; export default SubMenu; |
Now we are completed with the components folder now we manipulate the pages. Edit various pages for the sidebar in the project in src/pages:
Filename- AboutUs.js:
Javascript
import React from "react" ; export const AboutUs = () => { return ( <div className= "home" > <h1>neveropen About us</h1> </div> ); }; export const OurAim = () => { return ( <div className= "home" > <h1>neveropen Aim</h1> </div> ); }; export const OurVision = () => { return ( <div className= "home" > <h1>neveropen Vision</h1> </div> ); }; |
Filename- ContactUs.js:
Javascript
import React from "react" ; const Contact = () => { return ( <div className= "contact" > <h1>neveropen Contact us</h1> </div> ); }; export default Contact; |
Filename- Events.js:
Javascript
import React from "react" ; export const Events = () => { return ( <div className= "events" > <h1>GeeksForGeeks Events</h1> </div> ); }; export const EventsOne = () => { return ( <div className= "events" > <h1>neveropen Event1</h1> </div> ); }; export const EventsTwo = () => { return ( <div className= "events" > <h1>neveropen Event2</h1> </div> ); }; |
Filename- Services.js:
Javascript
import React from "react" ; export const Services = () => { return ( <div className= "services" > <h1>neveropen Services</h1> </div> ); }; export const ServicesOne = () => { return ( <div className= "services" > <h1>neveropen Service1</h1> </div> ); }; export const ServicesTwo = () => { return ( <div className= "services" > <h1>neveropen Service2</h1> </div> ); }; export const ServicesThree = () => { return ( <div className= "services" > <h1>neveropen Service3</h1> </div> ); }; |
Filename- Support.js:
Javascript
import React from "react" ; const Support = () => { return ( <div className= "support" > <h1>neveropen Support us</h1> </div> ); }; export default Support; |
All the pages and components are ready now we have to call them one by one in our App.js file.
Important Note: react-router-dom v6 or higher has replaced ‘Switch’ with ‘Routes’, and the old version of the app.js file code has now been updated as it did not support the use of Switch.
Filename- App.js:
Javascript
import "./App.css" ; import Sidebar from "./components/Sidebar" ; import { BrowserRouter as Router, Routes, Route } from "react-router-dom" ; import { AboutUs, OurAim, OurVision } from "./pages/AboutUs" ; import { Services, ServicesOne, ServicesTwo, ServicesThree, } from "./pages/Services" ; import { Events, EventsOne, EventsTwo } from "./pages/Events" ; import Contact from "./pages/ContactUs" ; import Support from "./pages/Support" ; function App() { return ( <Router> <Sidebar /> <Routes> <Route path= '/about-us' element={<AboutUs/>} /> <Route path= '/about-us/aim' element={<OurAim/>} /> <Route path= '/about-us/vision' element={<OurVision/>} /> <Route path= '/services' element={<Services/>} /> <Route path= '/services/services1' element={<ServicesOne/>} /> <Route path= '/services/services2' element={<ServicesTwo/>} /> <Route path= '/services/services3' element={<ServicesThree/>} /> <Route path= '/contact' element={<Contact/>} /> <Route path= '/events' element={<Events/>} /> <Route path= '/events/events1' element={<EventsOne/>} /> <Route path= '/events/events2' element={<EventsTwo/>} /> <Route path= '/support' element={<Support/>} /> </Routes> </Router> ); } export default App; |
Filename- App.css: modify the CSS according to you.
HTML
* { box-sizing: border-box; margin: 0; padding: 0; } .home, .services, .reports, .contact, .events, .support { display: flex; margin-left: 260px; font-size: 2rem; } |
Run the Project: Save all files and start the server by using the below command in your PowerShell terminal or IDE’s terminal.
npm start
Output: