VaneUI

VaneUI

Overlay Components

Menu

A dropdown menu triggered by a button with full keyboard navigation. Contains MenuItem, Divider, and MenuLabel subcomponents.

SourceEdit this page

A dropdown menu triggered by a button with full keyboard navigation. Contains MenuItem, MenuLabel, and Divider subcomponents.

When to Use

  • Action menus on a row or card (Edit / Duplicate / Delete).
  • Account / user menus in a header.
  • Overflow menus for secondary actions that don't fit in the toolbar.
  • Any disclosure where the items behave like commands — for navigation between pages, prefer NavLink.

Basic Menu

A dropdown menu triggered by a button. Pass the trigger as a React element via the trigger prop; children are the menu contents. Includes full keyboard navigation (Arrow keys, Enter, Escape, Tab) and focus management with a keyboard-visible outline on each item — focus returns to the trigger when the menu closes.

react-icon
import { Menu, MenuItem, Button } from "@vaneui/ui";
<Menu trigger={<Button>Actions</Button>}>
<MenuItem>Edit</MenuItem>
<MenuItem>Duplicate</MenuItem>
<MenuItem>Share</MenuItem>
</Menu>

Labels & Dividers

Use MenuLabel for section headings and Divider for visual separators between groups. Divider automatically picks up the Menu's size via the menu-divider sub-theme.

react-icon
<Menu trigger={<Button>Account</Button>}>
<MenuLabel>Account</MenuLabel>
<MenuItem>Profile</MenuItem>
<MenuItem>Settings</MenuItem>
<Divider />
<MenuLabel>Workspace</MenuLabel>
<MenuItem>Members</MenuItem>
<MenuItem>Billing</MenuItem>
<Divider />
<MenuItem>Sign out</MenuItem>
</Menu>

Items with Icons

Place SVG icons directly inside MenuItem — they are automatically flex-aligned and pointer-events-disabled so clicks pass through to the item.

react-icon
import { Edit, Copy, Trash2 } from "react-feather";
<Menu trigger={<Button>File</Button>}>
<MenuItem><Edit size={14} /> Edit</MenuItem>
<MenuItem><Copy size={14} /> Duplicate</MenuItem>
<Divider />
<MenuItem danger><Trash2 size={14} /> Delete</MenuItem>
</Menu>

Destructive Item

Use the danger appearance prop on a MenuItem to flag a destructive action. Combine with a Divider to visually separate it from safe actions.

react-icon
<Menu trigger={<Button>Manage</Button>}>
<MenuItem>Rename</MenuItem>
<MenuItem>Archive</MenuItem>
<Divider />
<MenuItem danger>Delete permanently</MenuItem>
</Menu>

Item Appearances

Any appearance prop works on MenuItem for semantic coloring of individual actions.

react-icon
<Menu trigger={<Button>Review</Button>}>
<MenuItem success>Approve</MenuItem>
<MenuItem warning>Request changes</MenuItem>
<MenuItem danger>Reject</MenuItem>
</Menu>

Disabled Items

Set disabled on a MenuItem to prevent interaction. Disabled items are skipped during keyboard navigation and announced via aria-disabled.

react-icon
<Menu trigger={<Button>Edit</Button>}>
<MenuItem>Undo</MenuItem>
<MenuItem disabled>Redo</MenuItem>
<Divider />
<MenuItem>Cut</MenuItem>
<MenuItem>Copy</MenuItem>
<MenuItem disabled>Paste</MenuItem>
</Menu>

Items as Links

Pass href to render a MenuItem as an anchor tag. For client-side navigation in a Next.js app, also pass tag={Link}.

react-icon
<Menu trigger={<Button>Navigate</Button>}>
<MenuItem href="/settings">Settings</MenuItem>
<MenuItem href="/profile">Profile</MenuItem>
<Divider />
<MenuItem href="https://github.com" target="_blank">GitHub</MenuItem>
</Menu>

Menu Sizes

Set a size on Menu (e.g. <Menu lg>) and the dropdown popup, every MenuItem, MenuLabel, and nested Divider scale together automatically — no need to repeat the size on every child. Items render with larger font-size and padding, the popup frame lifts its inner padding, and dividers match. Individual children can still override with their own size prop.

react-icon
<Menu lg trigger={<Button lg>Actions</Button>}>
<MenuLabel>Actions</MenuLabel>
<MenuItem>Edit</MenuItem>
<Divider />
<MenuItem danger>Delete</MenuItem>
</Menu>

Controlled State

Pass open and onOpenChange to drive the menu from outside state. Useful when you need to open the menu programmatically or react to its state.

react-icon
const [open, setOpen] = useState(false);
<Menu
open={open}
onOpenChange={setOpen}
trigger={<Button>Menu ({open ? "open" : "closed"})</Button>}
>
<MenuItem onClick={() => console.log("Edit")}>Edit</MenuItem>
<MenuItem closeMenuOnClick={false}>Stay open on click</MenuItem>
<MenuItem>Close on click (default)</MenuItem>
</Menu>

Advanced Props

Menu supports additional configuration for fine-tuning behavior:

PropDefaultDescription
openControlled open state
defaultOpenfalseInitial open state (uncontrolled)
onOpenChangeCalled when open state changes
onCloseCalled when the menu closes
closeOnItemClicktrueClose menu when any item is clicked
looptrueLoop keyboard navigation from last to first
disabledfalsePrevent menu from opening
transitionDuration150Animation duration in ms

MenuItem also accepts:

PropDefaultDescription
closeMenuOnClickinheritsOverride the menu-level closeOnItemClick for this item
hrefRender as anchor tag
disabledfalsePrevent interaction
focusVisibletrueRender a keyboard focus-visible outline
noFocusVisibleDisable the keyboard focus-visible outline

More in Overlay Components