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: