npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-mui-menu-button

v1.0.5

Published

Menu recursivo con N niveles para React con Material-UI

Readme

React Menu Button MUI

npm version

Recursive dropdown menu with support for multiple levels, navigation, smooth scrolling, and full customization. Built on Material UI and React Router.


Component for use in two themes

| Light Mode | Dark Mode | | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | White Menu | Black Menu |


📦 Installation

npm install react-mui-menu-button
# or
yarn add react-mui-menu-button
# or
pnpm add react-mui-menu-button

Required dependencies (peer dependencies)

Make sure the following libraries are installed in your project:

react >= 17.0.0
react-dom >= 17.0.0
@mui/material >= 5.0.0
@mui/icons-material >= 5.0.0
@emotion/react >= 11.0.0
@emotion/styled >= 11.0.0
react-router-dom >= 6.0.0

🚀 Basic Usage

import { DropdownWithSubmenu } from "react-mui-menu-button";
import { menuItems } from "./menuData"; // your MenuItem array

function App() {
  return <DropdownWithSubmenu menuItems={menuItems} triggerText="Explore" />;
}

📘 Data Structure (MenuItem)

Each menu item follows the interface:

interface MenuItem {
  label: string;          // Visible text
  href?: string;          // Navigation route (React Router)
  hash?: string;          // Internal scroll anchor (without #)
  icon: React.ReactNode;  // Icon (JSX element)
  children?: MenuItem[];  // Nested sub-items
}
  • ✅ You can combine href and hash.
  • ✅ If you only use hash, the nearest ancestor's href will be used as the base.
  • ✅ Items without href/hash and without children → do nothing when clicked.
  • ✅ Items without href/hash but with children → expand/collapse the submenu.

🧱 Quick menuItems Structure Example

import type { MenuItem } from "react-mui-menu-button";
import {
  Code as CodeIcon,
  GitHub as GitHubIcon,
  Article as ArticleIcon,
  Business as BusinessIcon,
  Person as PersonIcon,
} from "@mui/icons-material";

export const menuItems: MenuItem[] = [
  {
    label: "Technical Portfolio",
    href: "/portfolio",
    icon: <CodeIcon />,
    children: [
      {
        label: "Open Source Projects",
        hash: "open-source",
        icon: <GitHubIcon />,
        children: [
          {
            label: "React Components",
            hash: "react-components",
            icon: <CodeIcon />,
            children: [
              {
                label: "Advanced Components",
                hash: "advanced-components",
                icon: <CodeIcon />,
              },
              {
                label: "Custom Hooks",
                hash: "custom-hooks",
                icon: <CodeIcon />,
              },
            ],
          },
          {
            label: "Node.js Libraries",
            hash: "node-libraries",
            icon: <CodeIcon />,
          },
          {
            label: "UI Kits",
            hash: "ui-kits",
            icon: <CodeIcon />,
          },
        ],
      },
      {
        label: "Interactive Demos",
        hash: "demos",
        icon: <CodeIcon />,
        children: [
          {
            label: "Web Animations",
            hash: "web-animations",
            icon: <CodeIcon />,
          },
          {
            label: "REST APIs",
            hash: "rest-apis",
            icon: <CodeIcon />,
          },
        ],
      },
      {
        label: "Case Studies",
        hash: "case-studies",
        icon: <ArticleIcon />,
      },
      {
        label: "GitHub Repositories",
        hash: "repositories",
        icon: <GitHubIcon />,
      },
    ],
  },
  {
    label: "Ventures",
    href: "/ventures",
    icon: <BusinessIcon />,
    children: [
      {
        label: "Doors & Gates",
        hash: "doors-gates",
        icon: <BusinessIcon />,
        children: [
          {
            label: "Standard Models",
            hash: "standard-models",
            icon: <BusinessIcon />,
          },
          {
            label: "Custom Sizes",
            hash: "custom-measures",
            icon: <BusinessIcon />,
          },
        ],
      },
      {
        label: "Product Catalog",
        hash: "catalog",
        icon: <BusinessIcon />,
      },
      {
        label: "Custom Designs",
        hash: "designs",
        icon: <BusinessIcon />,
      },
    ],
  },
  {
    label: "Blog",
    href: "/blog",
    icon: <ArticleIcon />,
  },
  {
    label: "Profile",
    href: "/",
    icon: <PersonIcon />,
    children: [
      {
        label: "Technology Stack",
        hash: "technology-stack",
        icon: <CodeIcon />,
      },
      {
        label: "Work Experience",
        hash: "experience",
        icon: <PersonIcon />,
      },
    ],
  },
];

🧩 Main Props

1. Data and Content

| Prop | Type | Default | Description | | ----------- | ------------------------- | ---------------- | ------------------------------------- | | menuItems | MenuItem[] | defaultMenuItems | Array of menu items | | loading | boolean | false | Shows loading state | | loadingText | string | "Loading..." | Spinner text | | emptyState | React.ReactNode | undefined | Component when there are no items | | triggerText | string | React.ReactNode | "EXPLORE" | Text or element of the trigger button | | triggerIcon | React.ReactNode | undefined | Icon accompanying the button text |

2. Behavior

| Prop | Type | Default | Description | | ------------------- | -------------------- | ------- | ----------------------------------- | | onItemClick | (item, path) => void | - | Callback when clicking an item | | onHoverItem | (item, path) => void | - | Callback when hovering over an item | | onOpen | () => void | - | When the menu opens | | onClose | () => void | - | When the menu closes | | maxDepth | number | 5 | Maximum depth | | openOnHover | boolean | true | Open on hover | | closeOnClickOutside | boolean | true | Close when clicking outside | | closeDelay | number (ms) | 300 | Delay before closing |

3. Styles and Design

| Prop | Type | Default | Description | | ------------ | ---------------------------------- | -------- | ---------------- | | sx | SxProps<Theme> | - | Container styles | | paperSx | SxProps<Theme> | - | Paper styles | | itemSx | SxProps<Theme> | - | Item styles | | submenuSx | SxProps<Theme> | - | Submenu styles | | density | compact | standard | comfortable | standard | Vertical density | | showDividers | boolean | false | Show dividers | | dividerColor | string | divider | Divider color |

4. Icons

| Prop | Type | Default | Description | | ------------ | -------------------- | --------------- | -------------- | | expandIcon | React.ReactNode | ChevronRight | Closed submenu | | collapseIcon | React.ReactNode | ArrowDropUpIcon | Open submenu | | submenuIcon | React.ReactNode | expandIcon | Submenu icon | | iconPosition | start | end | none | end | Icon position |

5. Advanced Behavior

| Prop | Type | Default | Description | | --------------- | -------------- | ------- | ---------------- | | open | boolean | - | External control | | defaultOpen | boolean | false | Initial state | | initialDepth | number | 0 | Initial depth | | autoExpandDepth | number | 0 | Auto expansion | | scrollIntoView | boolean | true | Scroll by hash | | scrollOffset | number | 80 | Offset | | scrollBehavior | auto | smooth | smooth | Scroll type | | disabled | boolean | false | Disabled | | readOnly | boolean | false | Read only |

6. Accessibility and SEO

| Prop | Type | Default | Description | | ------------------ | ------- | ------------- | ------------------- | | ariaLabel | string | Dropdown menu | aria-label | | ariaLabelledBy | string | - | Label | | ariaDescribedBy | string | - | Description | | role | string | menu | ARIA role | | keyboardNavigation | boolean | true | Keyboard navigation | | focusOnOpen | boolean | true | Initial focus | | useAnchorTags | boolean | true | Uses <a> | | rel | string | - | rel attribute |

7. Internationalization

| Prop | Type | Default | Description | | ------------ | -------------------- | ------- | ----------- | | translations | DropdownTranslations | - | Texts | | direction | ltr | rtl | ltr | Direction |

8. Custom Rendering

| Prop | Type | Description | | ------------- | -------------------------- | -------------- | | renderTrigger | (props) => React.ReactNode | Custom trigger | | renderItem | (props) => React.ReactNode | Custom item | | renderSubmenu | (props) => React.ReactNode | Custom submenu |

9. Themes and Variants

| Prop | Type | Default | Description | | ----------- | ----------------------------------------------------------------- | ------- | -------------- | | variant | default | minimal | elevated | borderless | dark | gradient | default | Visual variant | | customTheme | CustomTheme | - | Custom theme |


🎨 Advanced Examples

Menu with click-to-open

<DropdownWithSubmenu
  menuItems={menuItems}
  openOnHover={false}
  closeOnClickOutside={true}
/>

Compact density

<DropdownWithSubmenu
  menuItems={menuItems}
  density="compact"
  iconPosition="none"
/>

Dark theme

<DropdownWithSubmenu
  menuItems={menuItems}
  variant="dark"
  customTheme={{
    colors: { background: "#1e1e2f", text: "#ffffff" },
    borderRadius: 8,
    spacing: 1,
  }}
/>

Custom trigger

<DropdownWithSubmenu
  menuItems={menuItems}
  renderTrigger={({ isOpen, toggle, ref }) => (
    <button ref={ref} onClick={toggle} className="my-button">
      {isOpen ? "Close" : "Open"} menu
    </button>
  )}
/>

Real links for SEO

<DropdownWithSubmenu
  menuItems={menuItems}
  useAnchorTags={true}
  rel="noopener noreferrer"
/>

♿ Accessibility

  • menu / menuitem roles
  • Keyboard navigation
  • ARIA attributes
  • Screen reader support

📐 TypeScript

import type {
  MenuItem,
  DropdownVariant,
  DropdownDensity,
  IconPosition,
  ScrollBehavior,
  CustomTheme,
  DropdownTranslations,
  DropdownWithSubmenuProps,
} from "recursive-dropdown-mui";

🛠️ Local Development

  1. Clone the repository
  2. Install dependencies: pnpm install
  3. Build: pnpm build
  4. Dev: pnpm dev

📄 License

MIT © BlackyCoder