Fri Sep 06 2024
Building Dashboard Menus with Recursive React Component
In web applications, especially in admin panels or dashboards, having a menu structure that can handle multiple levels of nesting is essential. One efficient way to achieve this in React (Next.js) is by using a recursive component. Recursive components are powerful because they can call themselves to render nested structures, such as deeply nested menus. Here, I’ll show you how to create a dynamic and recursive dashboard menu using React in a Next.js environment.
What is a Recursive Component?
A recursive component can render itself inside its render function. It’s useful for displaying structures that can have indefinite levels of depth, like a menu with sub menus, or a tree structure.
Step-by-Step Guide to Create a Recursive Dashboard Menu in Next.js
Step 1: Creating the Menu Data Structure
Let’s first define a menu structure that supports nesting. You can store this structure in a JSON file or in an object variable.
// Menu Structure Model
export class Menu {
name!: string;
link!: string;
subMenu!: Menu[];
}
// Menu Structure
const menuList: Menu[] = [
{ name: "Dashboard", link: "#", subMenu: [] },
{ name: "Report", link: "#", subMenu: [] },
{
name: "Product",
link: "#",
subMenu: [
{
name: "Product",
link: "#",
subMenu: [
{ name: "Add New", link: "#", subMenu: [] },
{ name: "List", link: "#", subMenu: [] },
],
},
{
name: "Inventory",
link: "#",
subMenu: [],
},
{
name: "Invoice",
link: "#",
subMenu: [],
},
],
},
{
name: "Business",
link: "#",
subMenu: [
{
name: "Outlet",
link: "#",
subMenu: [],
},
{
name: "Employee",
link: "#",
subMenu: [
{ name: "Add New", link: "#", subMenu: [] },
{ name: "List", link: "#", subMenu: [] },
],
},
{
name: "Shipment",
link: "#",
subMenu: [],
},
{
name: "Marketing",
link: "#",
subMenu: [],
},
],
},
{ name: "Settings", link: "#", subMenu: [] },
];
Step 2: Creating the Recursive Menu Component
Now, create a recursive component as a subMenu that will render the nested menu items. The key here is to check if a menu item has children. If it does, the component will recursively call itself to render the nested items.
const SubMenu = ({ sMenu }: { sMenu: Menu[] }) => {
const [subMenu, setSubMenu] = useState(false);
return (
<ul className="ml-6">
{sMenu.map((m: Menu, i: number) => {
return (
<li key={i} className="my-3">
{m.subMenu.length != 0 && (
<>
<a
onClick={() => setSubMenu(!subMenu)}
className="text-darkGray bg-white font-medium flex px-3 py-2 rounded-lg cursor-pointer shadow justify-between items-center"
>
{m.name}
<svg
width="549"
height="549"
viewBox="0 0 549 549"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={`w-3 h-3 fill-darkGray transition-all ${
subMenu ? "rotate-180" : "rotate-0"
}`}
>
<path d="M1.30957 169.97L273.55 444.58L546.78 169.97L481.57 103.51L273.55 321.7L62.7596 111.03L1.30957 169.97Z" />
</svg>
<div className={subMenu ? "block" : "hidden"}>
<SubMenu sMenu={m.subMenu} />
</div>
</>
)}
{m.subMenu.length == 0 && (
<>
<Link
href={m.link}
className="text-darkGray bg-white font-medium flex px-3 py-2 rounded-lg cursor-pointer shadow"
>
{m.name}
</Link>
</>
)}
</li>
);
})}
</ul>
);
};
export default SubMenu;
Step 3: Integrating the Recursive Component
To see the menu in action, let's integrate this recursive component inside our mainMenu component.
const MainMenu = ({ menu }: { menu: Menu }) => {
const [subMenu, setSubMenu] = useState(false);
return (
<li className="my-2">
{menu.subMenu.length != 0 && (
<>
<a
onClick={() => setSubMenu(!subMenu)}
className="px-3 py-2 bg-primary text-white font-medium rounded-lg flex w-full cursor-pointer shadow justify-between items-center"
>
{menu.name}
<svg
width="549"
height="549"
viewBox="0 0 549 549"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={`w-3 h-3 fill-white transition-all ${
subMenu ? "rotate-180" : "rotate-0"
}`}
>
<path d="M1.30957 169.97L273.55 444.58L546.78 169.97L481.57 103.51L273.55 321.7L62.7596 111.03L1.30957 169.97Z" />
</svg>
<div className={subMenu ? "block" : "hidden"}>
<SubMenu sMenu={menu.subMenu} />
</div>
</>
)}
{menu.subMenu.length == 0 && (
<Link
href={menu.link}
className="px-3 py-2 bg-primary text-white font-medium rounded-lg flex w-full cursor-pointer shadow"
>
{menu.name}
</Link>
)}
</li>
);
};
export default MainMenu;
In this example I’m using the React state variable to add a basic toggle button to expand and collapse the nested submenu items. You can download full project from WebGraphiz.com.
Conclusion
Creating a recursive menu component in React and Next.js allows for dynamic and flexible menus, especially in complex dashboard applications. With the help of Tailwind CSS or other CSS frameworks, you can style and structure your menus quickly. This approach provides a scalable solution for rendering deeply nested menus without needing to manually write out each level.
With Next.js, this method can be easily expanded to dynamically fetch menu data from an API, further improving flexibility in larger applications. By utilizing recursive components, you can keep your code clean, readable, and maintainable, making your development process more efficient.