Import
import {
Menu,
MenuArrow,
MenuArrowTip,
MenuContent,
MenuContextTrigger,
MenuItem,
MenuItemGroup,
MenuItemGroupLabel,
MenuOptionItem,
MenuPositioner,
MenuSeparator,
MenuTrigger,
MenuTriggerItem,
Portal,
} from '@ark-ui/react'
Usage
The Menu component consists of the MenuArrow
, MenuArrowTip
, MenuContent
,
MenuContextTrigger
, MenuItem
, MenuItemGroup
, MenuItemGroupLabel
,
MenuOptionItem
, MenuPositioner
, MenuSeparator
, MenuTrigger
and
MenuTriggerItem
components. Combine them as desired to fit your design system.
Note that the MenuTrigger
and MenuContextTrigger
components accept a single
JSX element which will receive all necessary props to add the event listeners
and attributes to ensure the desired accessibility.
<Menu>
<MenuTrigger>Open menu</MenuTrigger>
<Portal>
<MenuPositioner>
<MenuContent>
<MenuItem id="edit">Edit</MenuItem>
<MenuItem id="delete">Delete</MenuItem>
<MenuItem id="export">Export</MenuItem>
<MenuItem id="duplicate">Duplicate</MenuItem>
</MenuContent>
</MenuPositioner>
</Portal>
</Menu>
Listening to item selection
Pass the onSelect
prop to the Menu component to perform some custom logic when
an item is selected. The callback is invoked with the id
of the item.
<Menu onSelect={(id) => console.log(id)}>{/*...*/}</Menu>
Grouping menu items
When the number of menu items gets much, it might be useful to group related
menu items. To achieve this, render the MenuItemGroup
component around the
MenuItem
components. The MenuItemGroupLabel
component can be used to add a
label to the group.
<Menu>
<MenuTrigger>Open menu</MenuTrigger>
<Portal>
<MenuPositioner>
<MenuContent>
<MenuItemGroup id="accounts">
<MenuItemGroupLabel htmlFor="accounts">Accounts</MenuItemGroupLabel>
<MenuItem id="private">Private</MenuItem>
<MenuItem id="work">Work</MenuItem>
</MenuItemGroup>
<MenuItemGroup id="actions">
<MenuItemGroupLabel htmlFor="actions">Action</MenuItemGroupLabel>
<MenuItem id="rename">Rename</MenuItem>
<MenuItem id="delete">Delete</MenuItem>
</MenuItemGroup>
</MenuContent>
</MenuPositioner>
</Portal>
</Menu>
Separating menu items
To separate menu items, render the MenuSeparator
component.
<Menu>
<MenuTrigger>Open menu</MenuTrigger>
<Portal>
<MenuPositioner>
<MenuContent>
<MenuItem id="edit">Edit</MenuItem>
<MenuItem id="delete">Delete</MenuItem>
<MenuSeparator />
<MenuItem id="export">Export</MenuItem>
<MenuItem id="duplicate">Duplicate</MenuItem>
</MenuContent>
</MenuPositioner>
</Portal>
</Menu>
Context menu
To show the menu when a trigger element is right-clicked, use the
MenuContextTrigger
component.
Context menus are also opened during a long-press of roughly 700ms
when the
pointer is pen or touch.
<Menu>
<MenuContextTrigger>
<div
style={{ width: '100%', height: '20rem', border: '1px solid lightgray' }}
>
Some content
</div>
</MenuContextTrigger>
<Portal>
<MenuPositioner>
<MenuContent>
<MenuItem id="edit">Edit</MenuItem>
<MenuItem id="delete">Delete</MenuItem>
<MenuItem id="export">Export</MenuItem>
<MenuItem id="duplicate">Duplicate</MenuItem>
</MenuContent>
</MenuPositioner>
</Portal>
</Menu>
Nested menu
To show a nested menu, render another Menu
component and use the
MenuTriggerItem
component to open the submenu.
<Menu>
<MenuTrigger>Open menu</MenuTrigger>
<Portal>
<MenuPositioner>
<MenuContent>
<MenuItem id="new-tab">New Tab...</MenuItem>
<MenuItem id="new-win">New Window...</MenuItem>
<MenuSeparator />
<Menu>
<MenuTriggerItem>Share ></MenuTriggerItem>
<Portal>
<MenuPositioner>
<MenuContent>
<MenuItem id="twitter">Twitter</MenuItem>
<MenuItem id="message">Message</MenuItem>
</MenuContent>
</MenuPositioner>
</Portal>
</Menu>
</MenuContent>
</MenuPositioner>
</Portal>
</Menu>
Checkbox and Radio option items
To show a checkbox or radio option item, use the MenuOptionItem
component.
Depending on the type
prop, the item will be rendered as a checkbox or radio
option item. The name
prop is used to group the items together, and the
value
prop is used to identify the item.
To manage the state of the option items pass the value
and onValueChange
props to the Menu
component.
export const Options = () => {
const [value, setValue] = React.useState<Record<string, string | string[]>>({
framework: '',
libraries: [],
})
return (
<Menu
value={value}
onValueChange={(data) => {
setValue((prev) => ({
...prev,
[data.name]: data.value,
}))
}}
>
<MenuTrigger>Open menu</MenuTrigger>
<Portal>
<MenuPositioner>
<MenuContent>
<MenuItemGroup id="radio-group">
<MenuItemGroupLabel htmlFor="radio-group">
Radio Group
</MenuItemGroupLabel>
<MenuOptionItem name="framework" type="radio" value="react">
{(d) => <>{d.isActive ? '✅' : ''} React</>}
</MenuOptionItem>
<MenuOptionItem name="framework" type="radio" value="solid">
{(d) => <>{d.isActive ? '✅' : ''} Solid</>}
</MenuOptionItem>
<MenuOptionItem name="framework" type="radio" value="vue">
{(d) => <>{d.isActive ? '✅' : ''} Vue</>}
</MenuOptionItem>
</MenuItemGroup>
<MenuItemGroup id="checkbox-group">
<MenuItemGroupLabel htmlFor="checkbox-group">
Checkbox Group
</MenuItemGroupLabel>
<MenuOptionItem name="libraries" type="checkbox" value="zag-js">
{(d) => <>{d.isActive ? '✅' : ''} zag-js</>}
</MenuOptionItem>
<MenuOptionItem name="libraries" type="checkbox" value="ark">
{(d) => <>{d.isActive ? '✅' : ''} ark</>}
</MenuOptionItem>
<MenuOptionItem name="libraries" type="checkbox" value="panda">
{(d) => <>{d.isActive ? '✅' : ''} panda</>}
</MenuOptionItem>
<MenuOptionItem name="libraries" type="checkbox" value="chakra">
{(d) => <>{d.isActive ? '✅' : ''} chakra</>}
</MenuOptionItem>
</MenuItemGroup>
</MenuContent>
</MenuPositioner>
</Portal>
</Menu>
)
}