Menu

Combine a list of secondary actions into single interactive area
Import

Usage

import React from 'react';
import { Menu, MenuItem, MenuLabel, Divider, Text } from '@mantine/core';
function Demo() {
return (
<Menu>
<Menu.Label>Application</Menu.Label>
<Menu.Item icon={<GearIcon />}>Settings</Menu.Item>
<Menu.Item icon={<ChatBubbleIcon />}>Messages</Menu.Item>
<Menu.Item icon={<ImageIcon />}>Gallery</Menu.Item>
<Menu.Item
icon={<MagnifyingGlassIcon />}
rightSection={<Text size="xs" color="gray">K</Text>}
>
Search
</Menu.Item>
<Divider />
<Menu.Label>Danger zone</Menu.Label>
<Menu.Item icon={<PinRightIcon />}>Transfer my data</Menu.Item>,
<Menu.Item color="red" icon={<TrashIcon />}>Delete my account</Menu.Item>
</Menu>
);
}

Controlled

To control component opened state provide opened, onClose and onOpen props:

import { useState } from 'react';
import { Menu } from '@mantine/core';
function Demo() {
const [opened, setOpened] = useState(false);
return (
<Menu opened={opened} onOpen={() => setOpened(true)} onClose={() => setOpened(false)}>
{/* Menu items... */}
</Menu>
);
}

Show menu on hover

To show menu on hover set props:

  • trigger to hover
  • delay to number in ms (defaults to 0)

In this case menu will use onMouseEnter and onFocus events instead of onClick:

<Menu trigger="hover" delay={500} closeOnScroll={false}>
{/* ... menu items */}
</Menu>

Menu.Item component

You can use Divider (renders horizontal line) and Menu.Item components inside Menu. Menu.Item renders button and accepts props:

  • icon – icon on the left
  • children – item label
  • rightSection – any element, rendered on the right, for example, Badge or keyboard shortcut
  • ...others – Menu.Item produces button element, all other props will be spread to it, for example, onClick, style, className
<Menu.Item
icon={<GearIcon />}
onClick={() => console.log('Hello')}
rightSection={
<Text size="sm" color="gray">
K
</Text>
}
>
Label
</Menu.Item>

Custom control

By default menu button uses ActionIcon with horizontal dots. You can change it by setting control and controlRefProp props:

<Menu
control={<button type="button">Button control</button>}
controlRefProp="ref"
>
{/* Menu items */}
</Menu>
<Menu control={<Button>Mantine Button</Button>}>
{/* Menu items */}
</Menu>

controlRefProp is the prop name with which element ref can be accessed. It defaults to elementRef as all interactive Mantine components use it to get ref. For regular html element it will be controlRefProp="ref"

Change menu position

Menu is rendered inside Portal and its position is controlled with the following props:

  • position – left, right, bottom, top
  • placement – start, center, end
  • gutter – spacing between menu body and target element in px
  • withArrow – displays arrow, arrow position is calculated by position and placement props

Note that in most cases you will need to change Transition to match your position:

<Menu>
{/* Menu items */}
</Menu>

Change transition

Menu is built with Transition component. You can customize transition, timing function and duration:

<Menu
transition="rotate-right"
transitionDuration={100}
transitionTimingFunction="ease"
>
{/* Menu items */}
</Menu>

Size and shadow

You can use predefined shadows defined in theme.shadows or your own:

<Menu shadow="sm" /> // -> predefined small shadow
<Menu shadow="1px 1px 3px rgba(0, 0, 0, .1)" /> // -> custom shadow
Size
Shadow
<Menu>
{/* Menu items */}
</Menu>

Menu has predefined sizes: xs, sm, md, lg, xl. Size prop controls menu width. You can also use number value to set width in px:

<Menu size="sm" /> // -> predefined small width
<Menu size={200} /> // -> 200px width

You can get predefined menu sizes by importing MENU_SIZES:

import { MENU_SIZES } from '@mantine/core';
Prop valueMenu width
xs120px
sm160px
md200px
lg240px
xl300px

Custom component as Menu.Item

By default menu items render as button, to change that set component prop on Menu.Item component:

// Regular anchor as Menu.Item root element
<Menu.Item component="a" href="https://mantine/dev" target="_blank" />
// React router link as Menu.Item root element
<Menu.Item component={Link} to="/hello" />
<Menu>
<Menu.Item component="a" href="https://mantine.dev">
Mantine website
</Menu.Item>
<Menu.Item
icon={<ExternalLinkIcon />}
component="a"
href="https://mantine.dev"
target="_blank"
>
External link
</Menu.Item>
</Menu>

Menu.Item as Next.js Link

Next Link component requires ref prop usage, however all Mantine components use elementRef, to make Menu.Item and other similar components work with Next Link, create wrapper component in your components folder:

// This component can be reused in every Mantine component which supports component pass through
import React, { forwardRef } from 'react';
import Link from 'next/link';
export const NextLink = forwardRef(
(
{ href, ...others }: React.ComponentPropsWithoutRef<typeof Link>,
ref: React.ForwardedRef<HTMLAnchorElement>
) => (
<Link href={href}>
{/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
<a {...others} ref={ref} />
</Link>
)
);

And then pass it to Menu.Item or other component:

<Menu.Item component={NextLink} href="/hello">
Next Link menu item
</Menu.Item>

Customize behavior

You can control menu behavior with following props:

  • trapFocus – traps focus inside menu when it is opened
  • closeOnScroll – closes menu when page is scrolled

By default both options are true to ensure better accessibility, to turn them off set to false:

<Menu trapFocus={false} closeOnScroll={false} />

Store items separately

Menu does not support fragments, the following example will not work:

// Won't work, will not render items
const items = (
<>
<Menu.Item>First</Menu.Item>
<Menu.Item>Second</Menu.Item>
</>
);
<Menu>{items}</Menu>;

In case you want to store items separately use array instead of fragment:

// Works as expected
const items = [
<Menu.Item>First</Menu.Item>
<Menu.Item>Second</Menu.Item>
];
<Menu>{items}</Menu>;

Add your styles with styles API

You can customize add styles to any part of Menu with Styles API, for example, change hovered item color:

import { Menu, createStyles } from '@mantine/core';
const useStyles = createStyles((theme) => ({
itemHovered: {
backgroundColor: theme.colors[theme.primaryColor][7],
color: theme.white,
},
}));
function Demo() {
const classes = useStyles();
return (
<Menu classNames={classes}>
{/* Menu items... */}
</Menu>
);
}

Get element ref

You can get menu control ref by passing elementRef prop to Menu component:

import { useRef } from 'react';
import { Menu } from '@mantine/core';
function Demo() {
const menuControlRef = useRef();
return <Menu elementRef={menuControlRef} />;
}

Server side rendering

Component uses use-id hook to generate unique ids and aria- attributes, provide static menuId prop to prevent props mismatch:

<Menu /> // -> random id generated both on client and server, props mismatch warning
<Menu menuId="my-menu" /> // -> id is static, no mismatches

Accessibility and usability

To make component more accessible for users with screen readers set menuButtonLabel prop. Use it in case you chose control which does not include text, for example, default ActionIcon with horizontal dots icon.

Component behavior and properties:

  • When menu is opened focus is trapped inside
  • When menu is closed focus is moved back to menu control
  • Focus inside menu is controlled with up and down arrows, tab key has no effect
  • By default when menu item is clicked, menu closes, change it with closeOnItemClick prop
  • Menu is closed when user clicks outside ot presses escape
  • Menu control has aria-haspopup, aria-expanded, aria-controls and aria-label attributes, aria-label is defined by menuButtonLabel prop
  • Menu body has menu role, aria-orientation is always set to vertical
  • Menu item has menuitem role
Build fully functional accessible web applications with ease
Feedback
Your feedback is most valuable contribution to the project, please share how you use Mantine, what features are missing and what is done good
Leave feedback