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

better-mui-menu

v1.3.4

Published

MUI Menu enhancement for deeply nested menus with keyboard navigation and accessibility in mind.

Downloads

1,176

Readme

better-mui-menu

CI Security coverage npm version npm downloads License: MIT

better-mui-menu is a lightweight drop-in for Material UI that keeps a normal Menu structure while adding nested menus and full keyboard accessibility so nothing breaks audits or expectations in an MUI app.

Live demo

Try it:

StackBlitz playground.

Edit better-mui-menu-demo

Menu demo preview

Features

  • Unlimited nesting – describe every submenu with an items array and better-mui-menu renders NestedMenuItem poppers that stay synchronized with their parents.
  • Keyboard accessible – arrow keys, Enter/Space, and Escape behave like desktop menus, while focus management and ARIA attributes make the tree readable by assistive tech.
  • Data-driven API – you keep work in a single MenuItem[] list; leaves, dividers, and nested branches all live alongside each other.

Installation

npm install better-mui-menu

Since the component renders Material UI primitives, also install the peer dependencies:

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material

The @mui/icons-material peer is optional unless you use startIcon/endIcon helpers but we list it so consumers don’t need extra typings setup.

Usage

import { useState } from 'react'
import Button from '@mui/material/Button'
import Cloud from '@mui/icons-material/Cloud'
import Save from '@mui/icons-material/Save'
import { Menu, type MenuItem } from 'better-mui-menu'

const menuItems: MenuItem[] = [
  {
    id: 'save',
    label: 'Save',
    startIcon: Save,
    onClick: () => console.log('Save action'),
  },
  { type: 'divider' },
  {
    label: 'Cloud actions',
    startIcon: Cloud,
    items: [
      { label: 'Upload', onClick: () => console.log('Upload') },
      { label: 'Download', onClick: () => console.log('Download') },
    ],
  },
]

export function FileMenu() {
  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)

  return (
    <>
      <Button variant="contained" onClick={event => setAnchorEl(event.currentTarget)}>
        Open file menu
      </Button>
      <Menu
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={() => setAnchorEl(null)}
        items={menuItems}
      />
    </>
  )
}

Items shape

MenuItem extends @mui/material/MenuItemProps (excluding children) so you can still pass dense, disabled, divider, aria-selected, etc. The better-mui-menu shape adds:

  • type?: 'item' | 'divider' – render a Divider when 'divider' is supplied.
  • id?: string – optional stable ID for ARIA attributes; one is generated automatically otherwise.
  • label: ReactNode – the label shown in the menu row.
  • startIcon / endIcon – pass any SvgIconComponent to display icons consistently with Material UI.
  • items?: MenuItem[] – nested entries that render as submenus.
  • onClick?: MenuItemProps['onClick'] – leaves bubble clicks and close the menu stack so the consumer can handle the action.

Accessibility & interactions

  • Nested menus render in Popper instances positioned right-start from the trigger and fade in/out with a shared transition helper.
  • Hover keeps a submenu open while the mouse moves between trigger and popper; leaving the area closes the branch.
  • Keyboard navigation covers ArrowUp/ArrowDown through siblings, ArrowRight or Enter/Space to open children, ArrowLeft to back out, and Escape to dismiss every layer.
  • ARIA helpers (aria-haspopup, aria-controls, aria-expanded, aria-labelledby) are wired automatically so assistive tech understands the structure.

Development

The library lives inside package/better-mui-menu.

  • npm run dev – rebuilds src into dist with tsup --watch.
  • npm run build – creates production bundles ready for publication.
  • npm run test – runs the Jest suite located at src/**/*.test.{ts,tsx}.
  • npm run test:coverage – runs tests with coverage and writes reports to coverage/.

From the repository root you can use npm run dev:lib and npm run dev:demo together so the demo app consumes the rebuilt workspace link. Keep npm run dev (or npm run build) running before refreshing the demo because the Vite app imports the package via file:.