Components
Menu

Menu

An accessible dropdown and context menu that is used to display a list of actions or options that a user can choose.

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 &gt;</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>
  )
}

Previous

Hover Card