Skip to main content

Overview

Menu displays a list of choices on a temporary surface. It appears when users interact with a button, action, or other control. Menus are ideal for displaying contextual options and actions.

Installation

npm install @naturacosmeticos/natds-web

Import

import { Menu, MenuItem } from '@naturacosmeticos/natds-web';

Props

Inherits all props from Material-UI’s Menu component.
open
boolean
required
If true, the menu is visible.
anchorEl
Element | null
A HTML element, or a function that returns it. Used to position the menu.
onClose
function
Callback fired when the component requests to be closed.
children
ReactNode
Menu contents, typically MenuItem components.
anchorOrigin
object
Position of the menu relative to the anchor element. Default: { vertical: 'top', horizontal: 'left' }
transformOrigin
object
Position on the menu which will align with the anchor’s origin. Default: { vertical: 'top', horizontal: 'left' }
keepMounted
boolean
If true, the menu will not unmount when closed, improving performance.
variant
'menu' | 'selectedMenu'
The variant to use. Use "selectedMenu" for select-like behavior.
Inherits all props from Material-UI’s MenuItem component.
children
ReactNode
The content of the menu item.
onClick
function
Callback fired when the menu item is clicked.
selected
boolean
If true, the menu item is highlighted.
disabled
boolean
If true, the menu item is disabled.
button
boolean
If true, the menu item will behave like a button.

Usage

Basic Menu

import { Menu, MenuItem, Button } from '@naturacosmeticos/natds-web';
import { useState } from 'react';

function BasicMenu() {
  const [anchorEl, setAnchorEl] = useState(null);

  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <>
      <Button onClick={handleClick}>
        Open menu
      </Button>
      <Menu
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={handleClose}
      >
        <MenuItem onClick={handleClose}>Profile</MenuItem>
        <MenuItem onClick={handleClose}>My account</MenuItem>
        <MenuItem onClick={handleClose}>Logout</MenuItem>
      </Menu>
    </>
  );
}
import { Menu, MenuItem, Button, Icon } from '@naturacosmeticos/natds-web';
import { useState } from 'react';

function MenuWithIcons() {
  const [anchorEl, setAnchorEl] = useState(null);

  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <>
      <Button onClick={handleClick}>Options</Button>
      <Menu
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={handleClose}
      >
        <MenuItem onClick={handleClose}>
          <Icon name="outlined-action-edit" style={{ marginRight: 16 }} />
          Edit
        </MenuItem>
        <MenuItem onClick={handleClose}>
          <Icon name="outlined-content-copy" style={{ marginRight: 16 }} />
          Copy
        </MenuItem>
        <MenuItem onClick={handleClose}>
          <Icon name="outlined-action-delete" style={{ marginRight: 16 }} />
          Delete
        </MenuItem>
      </Menu>
    </>
  );
}
import { Menu, MenuItem, Button } from '@naturacosmeticos/natds-web';
import { useState } from 'react';

function MenuWithSelection() {
  const [anchorEl, setAnchorEl] = useState(null);
  const [selectedIndex, setSelectedIndex] = useState(1);

  const options = ['Profile', 'My account', 'Logout'];

  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  const handleMenuItemClick = (event, index) => {
    setSelectedIndex(index);
    handleClose();
  };

  return (
    <>
      <Button onClick={handleClick}>
        Open menu
      </Button>
      <Menu
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={handleClose}
        keepMounted
      >
        {options.map((option, index) => (
          <MenuItem
            key={option}
            button
            selected={index === selectedIndex}
            onClick={(event) => handleMenuItemClick(event, index)}
          >
            {option}
          </MenuItem>
        ))}
      </Menu>
    </>
  );
}

Context Menu

import { Menu, MenuItem } from '@naturacosmeticos/natds-web';
import { useState } from 'react';

function ContextMenu() {
  const [contextMenu, setContextMenu] = useState(null);

  const handleContextMenu = (event) => {
    event.preventDefault();
    setContextMenu(
      contextMenu === null
        ? { mouseX: event.clientX - 2, mouseY: event.clientY - 4 }
        : null
    );
  };

  const handleClose = () => {
    setContextMenu(null);
  };

  return (
    <div
      onContextMenu={handleContextMenu}
      style={{ cursor: 'context-menu', padding: 40, border: '1px dashed grey' }}
    >
      Right click here
      <Menu
        open={contextMenu !== null}
        onClose={handleClose}
        anchorReference="anchorPosition"
        anchorPosition={
          contextMenu !== null
            ? { top: contextMenu.mouseY, left: contextMenu.mouseX }
            : undefined
        }
      >
        <MenuItem onClick={handleClose}>Copy</MenuItem>
        <MenuItem onClick={handleClose}>Paste</MenuItem>
        <MenuItem onClick={handleClose}>Delete</MenuItem>
      </Menu>
    </div>
  );
}
import { Menu, MenuItem, Divider, Button } from '@naturacosmeticos/natds-web';
import { useState } from 'react';

function MenuWithDividers() {
  const [anchorEl, setAnchorEl] = useState(null);

  return (
    <>
      <Button onClick={(e) => setAnchorEl(e.currentTarget)}>
        Options
      </Button>
      <Menu
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={() => setAnchorEl(null)}
      >
        <MenuItem onClick={() => setAnchorEl(null)}>New File</MenuItem>
        <MenuItem onClick={() => setAnchorEl(null)}>Open</MenuItem>
        <Divider />
        <MenuItem onClick={() => setAnchorEl(null)}>Save</MenuItem>
        <MenuItem onClick={() => setAnchorEl(null)}>Save As</MenuItem>
        <Divider />
        <MenuItem onClick={() => setAnchorEl(null)}>Exit</MenuItem>
      </Menu>
    </>
  );
}

Positioned Menu

import { Menu, MenuItem, Button } from '@naturacosmeticos/natds-web';
import { useState } from 'react';

function PositionedMenu() {
  const [anchorEl, setAnchorEl] = useState(null);

  return (
    <>
      <Button onClick={(e) => setAnchorEl(e.currentTarget)}>
        Open Menu
      </Button>
      <Menu
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={() => setAnchorEl(null)}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'right',
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'right',
        }}
      >
        <MenuItem onClick={() => setAnchorEl(null)}>Option 1</MenuItem>
        <MenuItem onClick={() => setAnchorEl(null)}>Option 2</MenuItem>
        <MenuItem onClick={() => setAnchorEl(null)}>Option 3</MenuItem>
      </Menu>
    </>
  );
}
import { Menu, MenuItem, Button } from '@naturacosmeticos/natds-web';
import { useState } from 'react';

function ScrollableMenu() {
  const [anchorEl, setAnchorEl] = useState(null);
  const options = Array.from({ length: 20 }, (_, i) => `Option ${i + 1}`);

  return (
    <>
      <Button onClick={(e) => setAnchorEl(e.currentTarget)}>
        Long Menu
      </Button>
      <Menu
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={() => setAnchorEl(null)}
        PaperProps={{
          style: {
            maxHeight: 300,
            width: '20ch',
          },
        }}
      >
        {options.map((option) => (
          <MenuItem key={option} onClick={() => setAnchorEl(null)}>
            {option}
          </MenuItem>
        ))}
      </Menu>
    </>
  );
}

Nested Menus (Submenus)

import { Menu, MenuItem, Button } from '@naturacosmeticos/natds-web';
import { useState } from 'react';

function NestedMenu() {
  const [mainAnchor, setMainAnchor] = useState(null);
  const [subAnchor, setSubAnchor] = useState(null);

  return (
    <>
      <Button onClick={(e) => setMainAnchor(e.currentTarget)}>
        Open Menu
      </Button>
      <Menu
        anchorEl={mainAnchor}
        open={Boolean(mainAnchor)}
        onClose={() => setMainAnchor(null)}
      >
        <MenuItem onClick={() => setMainAnchor(null)}>Profile</MenuItem>
        <MenuItem onClick={(e) => setSubAnchor(e.currentTarget)}>
          Settings
        </MenuItem>
        <MenuItem onClick={() => setMainAnchor(null)}>Logout</MenuItem>
      </Menu>
      <Menu
        anchorEl={subAnchor}
        open={Boolean(subAnchor)}
        onClose={() => setSubAnchor(null)}
        anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
        transformOrigin={{ vertical: 'top', horizontal: 'left' }}
      >
        <MenuItem onClick={() => { setSubAnchor(null); setMainAnchor(null); }}>
          Account
        </MenuItem>
        <MenuItem onClick={() => { setSubAnchor(null); setMainAnchor(null); }}>
          Privacy
        </MenuItem>
        <MenuItem onClick={() => { setSubAnchor(null); setMainAnchor(null); }}>
          Notifications
        </MenuItem>
      </Menu>
    </>
  );
}

Composition

Menu works well with:
  • MenuItem: Individual items in the menu
  • MenuList: Wrapper for menu items when not using Menu
  • Divider: Separates groups of menu items
  • ListItemIcon: Icons within menu items
  • ListItemText: Text content within menu items

Best Practices

  • Keep menu options focused and relevant to the context
  • Use icons sparingly and consistently
  • Group related items and separate groups with dividers
  • Limit menu items to 7-10 for better usability
  • Use scrollable menus for longer lists
  • Disable unavailable options rather than hiding them
  • Provide keyboard navigation support

Accessibility

  • Menu items should be keyboard navigable (Arrow keys, Enter, Escape)
  • Press ESC to close the menu
  • Use ARIA labels for icon-only menu items
  • Disabled items should not be keyboard focusable
  • Ensure adequate color contrast for menu items
  • Screen readers announce menu state and selected items

Common Use Cases

  • User account menus
  • Context menus (right-click)
  • Action overflow menus (three-dot menus)
  • Dropdown selectors
  • Navigation menus
  • Settings and preferences

Material-UI Reference

This component is based on Material-UI’s Menu. For advanced usage, see the Material-UI Menu documentation.

Build docs developers (and LLMs) love