Ark Logo

Menu

A list of options that appears when a user interacts with a button.

Anatomy

To set up the menu correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Examples

Learn how to use the Menu component in your project. Let's take a look at the most basic example:

import { Menu } from '@ark-ui/react'

export const Basic = () => (
  <Menu.Root>
    <Menu.Trigger>
      Open menu <Menu.Indicator>➡️</Menu.Indicator>
    </Menu.Trigger>
    <Menu.Positioner>
      <Menu.Content>
        <Menu.Item value="react">React</Menu.Item>
        <Menu.Item value="solid">Solid</Menu.Item>
        <Menu.Item value="vue">Vue</Menu.Item>
      </Menu.Content>
    </Menu.Positioner>
  </Menu.Root>
)

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.

import { useState } from 'react'
import { Menu } from '@ark-ui/react'

export const Controlled = () => {
  const [isOpen, setIsOpen] = useState(false)

  return (
    <>
      <button type="button" onClick={() => setIsOpen(!isOpen)}>
        Trigger from the outside
      </button>
      <Menu.Root open={isOpen}>
        <Menu.Trigger>
          Open menu <Menu.Indicator>➡️</Menu.Indicator>
        </Menu.Trigger>
        <Menu.Positioner>
          <Menu.Content>
            <Menu.Item value="react">React</Menu.Item>
            <Menu.Item value="solid">Solid</Menu.Item>
            <Menu.Item value="vue">Vue</Menu.Item>
          </Menu.Content>
        </Menu.Positioner>
      </Menu.Root>
    </>
  )
}

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 Menu.ItemGroup component around the Menu.Item components. The Menu.ItemGroupLabel component can be used to add a label to the group.

import { Menu } from '@ark-ui/react'

export const Group = () => (
  <Menu.Root>
    <Menu.Trigger>Open menu</Menu.Trigger>
    <Menu.Positioner>
      <Menu.Content>
        <Menu.ItemGroup>
          <Menu.ItemGroupLabel>JS Frameworks</Menu.ItemGroupLabel>
          <Menu.Item value="react">React</Menu.Item>
          <Menu.Item value="solid">Solid</Menu.Item>
          <Menu.Item value="vue">Vue</Menu.Item>
        </Menu.ItemGroup>
        <Menu.ItemGroup>
          <Menu.ItemGroupLabel>CSS Frameworks</Menu.ItemGroupLabel>
          <Menu.Item value="panda">Panda</Menu.Item>
          <Menu.Item value="tailwind">Tailwind</Menu.Item>
        </Menu.ItemGroup>
      </Menu.Content>
    </Menu.Positioner>
  </Menu.Root>
)

Separating menu items

To separate menu items, render the Menu.Separator component.

import { Menu } from '@ark-ui/react'

export const Separator = () => (
  <Menu.Root>
    <Menu.Trigger>Open menu</Menu.Trigger>
    <Menu.Positioner>
      <Menu.Content>
        <Menu.Item value="react">React</Menu.Item>
        <Menu.Item value="solid">Solid</Menu.Item>
        <Menu.Separator />
        <Menu.Item value="vue">Vue</Menu.Item>
      </Menu.Content>
    </Menu.Positioner>
  </Menu.Root>
)

Context menu

To show the menu when a trigger element is right-clicked, use the Menu.ContextTrigger component.

Context menus are also opened during a long-press of roughly 700ms when the pointer is pen or touch.

import { Menu } from '@ark-ui/react'

export const Context = () => (
  <Menu.Root>
    <Menu.ContextTrigger>Right click me</Menu.ContextTrigger>
    <Menu.Positioner>
      <Menu.Content>
        <Menu.Item value="react">React</Menu.Item>
        <Menu.Item value="solid">Solid</Menu.Item>
        <Menu.Item value="vue">Vue</Menu.Item>
      </Menu.Content>
    </Menu.Positioner>
  </Menu.Root>
)

Nested menu

To show a nested menu, render another Menu component and use the Menu.TriggerItem component to open the submenu.

import { Menu } from '@ark-ui/react'
import { Portal } from '@ark-ui/react'

export const Nested = () => (
  <Menu.Root>
    <Menu.Trigger>Open menu</Menu.Trigger>
    <Menu.Positioner>
      <Menu.Content>
        <Menu.Root>
          <Menu.TriggerItem>JS Frameworks</Menu.TriggerItem>
          <Portal>
            <Menu.Positioner>
              <Menu.Content>
                <Menu.Item value="react">React</Menu.Item>
                <Menu.Item value="solid">Solid</Menu.Item>
                <Menu.Item value="vue">Vue</Menu.Item>
              </Menu.Content>
            </Menu.Positioner>
          </Portal>
        </Menu.Root>
        <Menu.Root>
          <Menu.TriggerItem>CSS Frameworks</Menu.TriggerItem>
          <Portal>
            <Menu.Positioner>
              <Menu.Content>
                <Menu.Item value="panda">Panda</Menu.Item>
                <Menu.Item value="tailwind">Tailwind</Menu.Item>
              </Menu.Content>
            </Menu.Positioner>
          </Portal>
        </Menu.Root>
      </Menu.Content>
    </Menu.Positioner>
  </Menu.Root>
)

Checkbox

To add a checkbox to a menu item, use the Menu.Checkbox component.

import { useState } from 'react'
import { Menu } from '@ark-ui/react'

export const Checkbox = () => {
  const [checked, setChecked] = useState(false)

  return (
    <Menu.Root>
      <Menu.Trigger>Open menu</Menu.Trigger>
      <Menu.Positioner>
        <Menu.Content>
          <Menu.CheckboxItem checked={checked} onCheckedChange={setChecked} value="checked">
            <Menu.ItemIndicator>✅</Menu.ItemIndicator>
            <Menu.ItemText>Check me</Menu.ItemText>
          </Menu.CheckboxItem>
        </Menu.Content>
      </Menu.Positioner>
    </Menu.Root>
  )
}

Radio Group

To group radio option items, use the Menu.RadioGroup component.

import { useState } from 'react'
import { Menu } from '@ark-ui/react'

export const RadioGroup = () => {
  const [value, setValue] = useState('React')

  return (
    <Menu.Root>
      <Menu.Trigger>Open menu</Menu.Trigger>
      <Menu.Positioner>
        <Menu.Content>
          <Menu.RadioItemGroup value={value} onValueChange={(e) => setValue(e.value)}>
            <Menu.ItemGroupLabel>JS Frameworks</Menu.ItemGroupLabel>
            {['React', 'Solid', 'Vue'].map((framework) => (
              <Menu.RadioItem key={framework} value={framework}>
                <Menu.ItemIndicator>✅</Menu.ItemIndicator>
                <Menu.ItemText>{framework}</Menu.ItemText>
              </Menu.RadioItem>
            ))}
          </Menu.RadioItemGroup>
        </Menu.Content>
      </Menu.Positioner>
    </Menu.Root>
  )
}

API Reference

Root

PropDefaultType
anchorPoint
Point

The positioning point for the menu. Can be set by the context menu trigger or the button trigger.

aria-label
string

The accessibility label for the menu

closeOnSelecttrue
boolean

Whether to close the menu when an option is selected

compositetrue
boolean

Whether the menu is a composed with other composite widgets like a combobox or tabs

defaultOpen
boolean

The initial open state of the menu when it is first rendered. Use when you do not need to control its open state.

highlightedValue
string

The value of the highlighted menu item.

id
string

The unique identifier of the machine.

ids
Partial<{ trigger: string contextTrigger: string content: string label(id: string): string group(id: string): string positioner: string arrow: string }>

The ids of the elements in the menu. Useful for composition.

lazyMountfalse
boolean

Whether to enable lazy mounting

loopFocusfalse
boolean

Whether to loop the keyboard navigation.

onEscapeKeyDown
(event: KeyboardEvent) => void

Function called when the escape key is pressed

onExitComplete
() => void

Function called when the animation ends in the closed state.

onFocusOutside
(event: FocusOutsideEvent) => void

Function called when the focus is moved outside the component

onHighlightChange
(details: HighlightChangeDetails) => void

Function called when the highlighted menu item changes.

onInteractOutside
(event: InteractOutsideEvent) => void

Function called when an interaction happens outside the component

onOpenChange
(details: OpenChangeDetails) => void

Function called when the menu opens or closes

onPointerDownOutside
(event: PointerDownOutsideEvent) => void

Function called when the pointer is pressed down outside the component

onSelect
(details: SelectionDetails) => void

Function called when a menu item is selected.

open
boolean

Whether the menu is open

positioning
PositioningOptions

The options used to dynamically position the menu

present
boolean

Whether the node is present (controlled by the user)

typeaheadtrue
boolean

Whether the pressing printable characters should trigger typeahead navigation

unmountOnExitfalse
boolean

Whether to unmount on exit.

Arrow

PropDefaultType
asChild
boolean

Render as a different element type.

ArrowTip

PropDefaultType
asChild
boolean

Render as a different element type.

CheckboxItem

PropDefaultType
checked
boolean

Whether the option is checked

value
string

The value of the option

asChild
boolean

Render as a different element type.

closeOnSelect
boolean

Whether the menu should be closed when the option is selected.

disabled
boolean

Whether the menu item is disabled

onCheckedChange
(checked: boolean) => void

Function called when the option state is changed

valueText
string

The textual value of the option. Used in typeahead navigation of the menu. If not provided, the text content of the menu item will be used.

Content

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]menu
[data-part]content
[data-state]"open" | "closed"
[data-placement]The placement of the content

ContextTrigger

PropDefaultType
asChild
boolean

Render as a different element type.

Indicator

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]menu
[data-part]indicator
[data-state]"open" | "closed"

ItemGroupLabel

PropDefaultType
asChild
boolean

Render as a different element type.

ItemGroup

PropDefaultType
asChild
boolean

Render as a different element type.

id
string

The `id` of the element that provides accessibility label to the option group

ItemIndicator

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]menu
[data-part]item-indicator
[data-disabled]Present when disabled
[data-highlighted]Present when highlighted
[data-state]"checked" | "unchecked"

Item

PropDefaultType
value
string

The unique value of the menu item option.

asChild
boolean

Render as a different element type.

closeOnSelect
boolean

Whether the menu should be closed when the option is selected.

disabled
boolean

Whether the menu item is disabled

valueText
string

The textual value of the option. Used in typeahead navigation of the menu. If not provided, the text content of the menu item will be used.

Data AttributeValue
[data-scope]menu
[data-part]item
[data-disabled]Present when disabled
[data-highlighted]Present when highlighted
[data-valuetext]The human-readable value

ItemText

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]menu
[data-part]item-text
[data-disabled]Present when disabled
[data-highlighted]Present when highlighted
[data-state]"checked" | "unchecked"

Positioner

PropDefaultType
asChild
boolean

Render as a different element type.

RadioItemGroup

PropDefaultType
asChild
boolean

Render as a different element type.

id
string

onValueChange
(e: ValueChangeDetails) => void

value
string

RadioItem

PropDefaultType
value
string

The value of the option

asChild
boolean

Render as a different element type.

closeOnSelect
boolean

Whether the menu should be closed when the option is selected.

disabled
boolean

Whether the menu item is disabled

valueText
string

The textual value of the option. Used in typeahead navigation of the menu. If not provided, the text content of the menu item will be used.

Separator

PropDefaultType
asChild
boolean

Render as a different element type.

TriggerItem

PropDefaultType
asChild
boolean

Render as a different element type.

Trigger

PropDefaultType
asChild
boolean

Render as a different element type.

Data AttributeValue
[data-scope]menu
[data-part]trigger
[data-placement]The placement of the trigger
[data-state]"open" | "closed"

Accessibility

Complies with the Menu WAI-ARIA design pattern.

Keyboard Support

KeyDescription
Space
Activates/Selects the highlighted item
Enter
Activates/Selects the highlighted item
ArrowDown
Highlights the next item in the menu
ArrowUp
Highlights the previous item in the menu
ArrowRightArrowLeft
When focus is on trigger, opens or closes the submenu depending on reading direction.
Esc
Closes the menu and moves focus to the trigger