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>
)
}