Multilevel dropdown menu with responsive design creating in ReactJS
Multilevel dropdown menus are a staple of web design. With the ability to provide multiple options to select from, they make navigation bars dynamic and organized. For any developer working in React or any React-based project like Gatsby or Next.js, this tutorial covers the step-by-step process of how to implement the dropdown feature in a React project.
Setting up the React project
Let’s start by creating a new React project called multilevel-menu
by running the following command:
npx create-react-app multilevel-menu
Once the project generates, navigate inside the project folder using cd multilevel-menu
or simply open the project with a code editor.
Then, run the npm start
built-in command to start the project in development mode. The app should launch in the browser at http://localhost:3000.
Creating the project files
Head over to the src
folder and delete all the files except the index.js
. Next, create a folder called components
inside the src
and add the following component files: DropDownMenu.js
, MenuItem.js
and DropDownSubMenu.js
.
In the App.js
file, add the following starting code:
import React from 'react'; import { Container, Nav, Navbar, Row, Col, NavDropdown } from 'react-bootstrap'; import './App.css'; import { DropDownMenu } from './components/Dropdownmenu'; import { DropDownSubMenu } from './components/dropdownsubmenu'; const App = () => ( <> <Navbar bg="dark" expand="lg" variant="dark"> <Container> <Navbar.Brand href="#home">Devhubspot</Navbar.Brand> <Navbar.Toggle aria-controls="basic-navbar-nav" /> <Navbar.Collapse id="basic-navbar-nav"> <Nav className="me-auto"> <Nav.Link href="#home">Home</Nav.Link> <DropDownMenu title="Services" id="collasible-nav-dropdown"> <NavDropdown.Item href="#action/3.1">Web Development</NavDropdown.Item> <DropDownSubMenu href="#action/3.7" title="Deisgn"> <NavDropdown.Item href="#action/8.1">Html</NavDropdown.Item> <NavDropdown.Item href="#action/8.2">CSS</NavDropdown.Item> <DropDownSubMenu href="#action/3.7" title="Development"> <NavDropdown.Item href="#action/9.1">Javascript</NavDropdown.Item> <NavDropdown.Item href="#action/9.2">Jquery</NavDropdown.Item> </DropDownSubMenu> </DropDownSubMenu> </DropDownMenu> </Nav> <Nav> <DropDownMenu title="Product" id="collasible-nav-dropdown" alignRight> <DropDownSubMenu href="#action/3.7" title="Language"> <NavDropdown.Item href="#action/8.1">React</NavDropdown.Item> <NavDropdown.Item href="#action/8.2">Anguler</NavDropdown.Item> <NavDropdown.Item href="#action/8.3">Ionic</NavDropdown.Item> <DropDownSubMenu href="#action/3.7" title="backend"> <NavDropdown.Item href="#action/9.1">Nodejs</NavDropdown.Item> <NavDropdown.Item href="#action/9.1">PHP</NavDropdown.Item> <NavDropdown.Item href="#action/9.1">JAVA</NavDropdown.Item> </DropDownSubMenu> </DropDownSubMenu> </DropDownMenu> </Nav> </Navbar.Collapse> </Container> </Navbar> <Container> <Row> <Col> <h1>React Multi Level Dropdown Menu With Mobile responsive</h1> </Col> </Row> </Container> </> ); export default App;
Open the components/
DropDownSubMenu.js file and add the following code:
import * as React from 'react'; export const DropDownSubMenu = (props) =>{ let refSubMenuContent = React.useRef(HTMLDivElement); let className = 'dropdown-submenu-container'; className = props.className ? className + ' ' + props.className : className; const onClick = (event) => { event.preventDefault(); event.stopPropagation(); if (refSubMenuContent.current) { let show = false; if (refSubMenuContent.current.classList.contains('show')) { hideChildren(refSubMenuContent.current); } else { show = true; hideSiblings(); } refSubMenuContent.current.classList.toggle('show'); if (typeof props.onToggle === 'function') { props.onToggle(show, { source: 'select' , originalEvent: event}); } } }; const hideSiblings = () => { if (refSubMenuContent.current) { const parents = getParents( refSubMenuContent.current, '.dropdown-menu.show' ); if (parents.length > 1) { hideChildren(parents[1]); } } }; const hideChildren = (parent) => { const children = parent.querySelectorAll('.dropdown-menu.show'); for (const child of children) { child.classList.remove('show'); } } const getParents = (elem, selector) => { const nodes = []; let element = elem; nodes.push(element); while (element.parentNode) { if ( typeof element.parentNode.matches === 'function' && element.parentNode.matches(selector) ) { nodes.push(element.parentNode); } element = element.parentNode; } return nodes; } return ( <div className={className} id={props.id}> <a href={props.href} className="dropdown-item dropdown-submenu dropdown-toggle" onClick={onClick} > {props.title} </a> <div className="dropdown-menu" ref={refSubMenuContent} > {props.children} </div> </div> ); }
Open the components/MenuItems.js
file and add the following code:
import * as React from 'react'; import { Dropdown } from 'react-bootstrap'; export const MenuItem = (props) =>{ const onSelect = (event) => { if (typeof props.onSelect === 'function') { props.onSelect(event); } }; return ( <Dropdown.Item id={props.id} href={props.href} title={props.title} className={props.className} onSelect={onSelect} active={props.active} disabled={props.disabled} onClick={props.onClick} > {props.children} </Dropdown.Item> ); }
Let’s now open the components/DropDownMenu.js
file and access the prop so we can render the menu
like so:
import * as React from 'react'; import { NavDropdown } from 'react-bootstrap'; export const DropDownMenu = (props) =>{ let divEl = React.useRef(HTMLDivElement); const onToggle = ( show, meta ) => { if (divEl.current) { if (show === false) { const element = divEl.current; if (element) { const children = element.querySelectorAll('.dropdown-menu.show'); // @ts-ignore for (const child of children) { child.classList.remove('show'); } } } } if (typeof props.onToggle === 'function') { props.onToggle(show, meta); } }; return ( <NavDropdown ref={divEl} className={props.className} title={props.title} id={props.id} onToggle={onToggle} align={props.alignRight ? "end" : undefined} disabled={props.disabled} active={props.active} menuRole={props.menuRole} renderMenuOnMount={props.renderMenuOnMount} rootCloseEvent={props.rootCloseEvent} bsPrefix={props.bsPrefix} drop={props.drop} show={props.show} focusFirstItemOnShow={props.focusFirstItemOnShow} > {props.children} </NavDropdown> ); }
Open the src/app.css
file and temporarily comment-out the display: none;
part of the CSS:
.header { text-align: center; } #nav { background-color: red; color: red; } .toast { margin: 0 auto; } .custom-btn-toolbar { display: inline !important; } .custom-btn-toolbar > .btn { margin-right: 1rem; } .dropdown-submenu-container { position: relative; } .dropdown-submenu-container a.dropdown-submenu::after { transform: rotate(-90deg); position: absolute; right: 6px; top: 0.8em; } .dropdown-menu-right .dropdown-submenu-container a.dropdown-submenu::after { transform: rotate(90deg); position: absolute; left: 0px; right: unset; top: 0.8em; } .dropdown-menu-end .dropdown-submenu-container a.dropdown-submenu::after { transform: rotate(90deg); position: absolute; left: 0px; right: unset; top: 0.8em; } .dropdown-submenu-container .dropdown-menu { top: 0; left: 100%; margin-left: 1px; margin-right: auto; } .dropdown-menu-right .dropdown-submenu-container .dropdown-menu { left: auto; right: 100%; margin-left: auto; margin-right: 1px; } .dropdown-menu-end .dropdown-submenu-container .dropdown-menu { left: auto; right: 100%; margin-left: auto; margin-right: 1px; }
add bootstrap css file index.js load css
import "bootstrap/dist/css/bootstrap.css";
Save and Update the file and test your project.Thanks
Output: