Menu

Combine a list of secondary actions into single interactive area
Import

Usage

import { Menu, Button, Text } from '@mantine/core';
import { IconSettings, IconSearch, IconPhoto, IconMessageCircle, IconTrash, IconArrowsLeftRight } from '@tabler/icons';
function Demo() {
return (
<Menu shadow="md" width={200}>
<Menu.Target>
<Button>Toggle menu</Button>
</Menu.Target>
<Menu.Dropdown>
<Menu.Label>Application</Menu.Label>
<Menu.Item icon={<IconSettings size={14} />}>Settings</Menu.Item>
<Menu.Item icon={<IconMessageCircle size={14} />}>Messages</Menu.Item>
<Menu.Item icon={<IconPhoto size={14} />}>Gallery</Menu.Item>
<Menu.Item
icon={<IconSearch size={14} />}
rightSection={<Text size="xs" color="dimmed">K</Text>}
>
Search
</Menu.Item>
<Menu.Divider />
<Menu.Label>Danger zone</Menu.Label>
<Menu.Item icon={<IconArrowsLeftRight size={14} />}>Transfer my data</Menu.Item>
<Menu.Item color="red" icon={<IconTrash size={14} />}>Delete my account</Menu.Item>
</Menu.Dropdown>
</Menu>
);
}

Controlled

Dropdown opened state can be controlled with opened and onChange props:

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

Show menu on hover

Set trigger="hover" to reveal dropdown when hovers over menu target and dropdown. closeDelay and openDelay props can be used to control open and close delay in ms. Note that:

  • If you set closeDelay={0} then menu will close before user will reach dropdown, set offset={0} to remove space between target element and dropdown
  • Menu with trigger="hover" is not accessible – users that navigate with keyboard will not be able to use it
import { Menu } from '@mantine/core';
function Demo() {
return (
<Menu trigger="hover" openDelay={100} closeDelay={400}>
{/* ... menu items */}
</Menu>
);
}

Disabled items

import { Menu, Button } from '@mantine/core';
import { IconSearch } from '@tabler/icons';
function Demo() {
return (
<Menu>
<Menu.Target>
<Button>Toggle menu</Button>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item icon={<IconSearch size={14} />} disabled>
Search
</Menu.Item>
{/* Other items ... */}
</Menu.Dropdown>
</Menu>
);
}

Dropdown position

import { Menu } from '@mantine/core';
function Demo() {
return (
<Menu>
{/* Menu items */}
</Menu>
);
}

Transitions

Menu dropdown can be animated with any of premade transitions from Transition component:

import { Menu } from '@mantine/core';
function Demo() {
return (
<Menu transition="rotate-right" transitionDuration={150}>
{/* Menu content */}
</Menu>
);
}

Custom component as Menu.Item

By default, Menu.Item renders as button element, to change that set component prop:

import { Menu, Button } from '@mantine/core';
import { IconExternalLink } from '@tabler/icons';
function Demo() {
return (
<Menu width={200} shadow="md">
<Menu.Target>
<Button>Toggle menu</Button>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item component="a" href="https://mantine.dev">
Mantine website
</Menu.Item>
<Menu.Item
icon={<IconExternalLink size={14} />}
component="a"
href="https://mantine.dev"
target="_blank"
>
External link
</Menu.Item>
</Menu.Dropdown>
</Menu>
);
}

Custom component as target

import { forwardRef } from 'react';
import { IconChevronRight } from '@tabler/icons';
import { Group, Avatar, Text, Menu, UnstyledButton } from '@mantine/core';
interface UserButtonProps extends React.ComponentPropsWithoutRef<'button'> {
image: string;
name: string;
email: string;
icon?: React.ReactNode;
}
const UserButton = forwardRef<HTMLButtonElement, UserButtonProps>(
({ image, name, email, icon, ...others }: UserButtonProps, ref) => (
<UnstyledButton
ref={ref}
sx={(theme) => ({
display: 'block',
width: '100%',
padding: theme.spacing.md,
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.black,
'&:hover': {
backgroundColor:
theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.colors.gray[0],
},
})}
{...others}
>
<Group>
<Avatar src={image} radius="xl" />
<div style={{ flex: 1 }}>
<Text size="sm" weight={500}>
{name}
</Text>
<Text color="dimmed" size="xs">
{email}
</Text>
</div>
{icon || <IconChevronRight size={16} />}
</Group>
</UnstyledButton>
)
);
function Demo() {
return (
<Group position="center">
<Menu withArrow>
<Menu.Target>
<UserButton
image="https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=255&q=80"
name="Harriette Spoonlicker"
email="hspoonlicker@outlook.com"
/>
</Menu.Target>
{/* ...Menu.Items */}
</Menu>
</Group>
);
}

Styles API

You can use the following data- attributes to customize menu styles:

  • data-expanded – added to target element when menu is opened (see previous demo)
  • data-hovered – added to item when it is hovered with mouse or selected with up/down arrows
import { Menu, createStyles } from '@mantine/core';
const useStyles = createStyles((theme) => ({
item: {
'&[data-hovered]': {
backgroundColor: theme.colors[theme.primaryColor][theme.fn.primaryShade()],
color: theme.white,
},
},
}));
function Demo() {
const { classes } = useStyles();
return (
<Menu classNames={classes}>
{/* Menu content... */}
</Menu>
);
}

Accessibility

Menu follows WAI-ARIA recommendations:

  • Dropdown element has role="menu" and aria-labelledby="target-id" attributes
  • Target element has aria-haspopup="menu", aria-expanded, aria-controls="dropdown-id" attributes
  • Menu item has role="menuitem" attribute

Supported target elements

Uncontrolled Menu with trigger="click" (default) will be accessible only when used with button element or component that renders it (Button, ActionIcon, etc.). Other elements will not support Space and Enter key presses.

Hover menu

Menu with trigger="hover" is not accessible – it cannot be accessed with keyboard, use it only if you do not care about accessibility.

Keyboard interactions

KeyDescriptionCondition
EscapeCloses dropdownFocus within dropdown
Space/EnterOpens/closes dropdownFocus on target element
ArrowUpMoves focus to previous menu itemFocus within dropdown
ArrowDownMoves focus to next menu itemFocus within dropdown
HomeMoves focus to first menu itemFocus within dropdown
EndMoves focus to last menu itemFocus within dropdown

Menu component props

NameTypeDescription
arrowOffset
number
Arrow offset in px
arrowPosition
"center" | "side"
Arrow position *
arrowRadius
number
Arrow radius in px
arrowSize
number
Arrow size in px
children
ReactNode
Menu content
clickOutsideEvents
string[]
Events that trigger outside clicks
closeDelay
number
Close delay in ms, applicable only to trigger="hover" variant
closeOnClickOutside
boolean
Determines whether dropdown should be closed on outside clicks, default to true
closeOnEscape
boolean
Determines whether dropdown should be closed when Escape key is pressed, defaults to true
closeOnItemClick
boolean
Determines whether Menu should be closed when item is clicked
defaultOpened
boolean
Uncontrolled menu initial opened state
disabled
boolean
If set, popover dropdown will not render
exitTransitionDuration
number
Exit transition duration in ms
id
string
id base to create accessibility connections
loop
boolean
Determines whether arrow key presses should loop though items (first to last and last to first)
middlewares
PopoverMiddlewares
Floating ui middlewares to configure position handling
offset
number
Space between target element and dropdown in px
onChange
(opened: boolean) => void
Called when menu opened state changes
onClose
() => void
Called when Menu is closed
onOpen
() => void
Called when Menu is opened
onPositionChange
(position: FloatingPosition) => void
Called when dropdown position changes
openDelay
number
Open delay in ms, applicable only to trigger="hover" variant
opened
boolean
Controlled menu opened state
position
"bottom" | "left" | "right" | "top" | "bottom-end" | "bottom-start" | "left-end" | "left-start" | "right-end" | "right-start" | "top-end" | "top-start"
Dropdown position relative to target
positionDependencies
any[]
useEffect dependencies to force update dropdown position
radius
number | "xs" | "sm" | "md" | "lg" | "xl"
Radius from theme.radius or number to set border-radius in px
returnFocus
boolean
Determines whether focus should be automatically returned to control when dropdown closes, false by default
shadow
MantineShadow
Key of theme.shadow or any other valid css box-shadow value
transition
MantineTransition
One of premade transitions ot transition object
transitionDuration
number
Transition duration in ms
trigger
"click" | "hover"
Event which should open menu
width
PopoverWidth
Dropdown width, or 'target' to make dropdown width the same as target element
withArrow
boolean
Determines whether component should have an arrow
withinPortal
boolean
Determines whether dropdown should be rendered within Portal, defaults to false
zIndex
ZIndex
Dropdown z-index

MenuItem component props

NameTypeDescription
children
ReactNode
Item label
closeMenuOnClick
boolean
Determines whether menu should be closed when item is clicked, overrides closeOnItemClick prop on Menu component
color
MantineColor
Key of theme.colors
icon
ReactNode
Icon rendered on the left side of the label
rightSection
ReactNode
Section rendered on the right side of the label

MenuDropdown component props

NameTypeDescription
children
ReactNode
Item label

MenuTarget component props

NameTypeDescription
children *
ReactNode
Target element
refProp
string
Key of the prop that should be used to get element ref

Menu component Styles API

NameStatic selectorDescription
dropdown.mantine-Menu-dropdownMenu.Dropdown element
label.mantine-Menu-labelMenu.Label root element
item.mantine-Menu-itemMenu.Item root element
arrow.mantine-Menu-arrowMenu.Dropdown arrow
divider.mantine-Menu-dividerMenu.Divider root element
itemIcon.mantine-Menu-itemIconMenu.Item icon
itemLabel.mantine-Menu-itemLabelMenu.Item label
itemRightSection.mantine-Menu-itemRightSectionMenu.Item right section