|Kit

Menu

A dropdown of actions on Ark UI's Menu — composable parts plus a typesafe data-driven form, with sections, submenus, checkbox / radio items, and a context-menu trigger.

Menu is the kit's dropdown of actions, a styled layer over Ark UI's Menu. Ark owns the open state, positioning, roving focus, type-ahead, and the role="menu" / menuitem ARIA wiring; the kit adds the portaled, animated surface and Mantine-style item props. It ships two APIs from one import — compose the parts for full control, or pass an items array for the common case.

import { Menu } from '@42/ui-react/menu';

<Menu.Root>
  <Menu.Trigger asChild>
    <Button>Open</Button>
  </Menu.Trigger>
  <Menu.Content>
    <Menu.Item startSection={<User />} onClick={openProfile}>Profile</Menu.Item>
    <Menu.Divider />
    <Menu.Item color="red" startSection={<Trash />} onClick={remove}>Delete</Menu.Item>
  </Menu.Content>
</Menu.Root>

Playground

Menu

Loading preview

Props

Code

<Menu  position="bottom-start"  offset={8}  closeOnSelect  loopFocus={false}/>

Basic usage

Menu.Item takes startSection / endSection (RTL-aware, like Mantine's left/right sections) and a color for destructive actions. Menu.Label heads a section and Menu.Divider separates them. The dropdown is portaled (escapes overflow: hidden ancestors) and animated.

Code

<Menu.Root><Menu.Trigger asChild>  <Button variant="default" endSlot={<ChevronDown />}>Account</Button></Menu.Trigger><Menu.Content>  <Menu.Label>Application</Menu.Label>  <Menu.Item startSection={<User />}>Profile</Menu.Item>  <Menu.Item startSection={<Settings />} endSection={<span>⌘S</span>}>Settings</Menu.Item>  <Menu.Item startSection={<Users />}>Team</Menu.Item>  <Menu.Divider />  <Menu.Item startSection={<LogOut />}>Log out</Menu.Item>  <Menu.Item color="red" startSection={<Trash2 />}>Delete account</Menu.Item></Menu.Content></Menu.Root>

Data-driven

For simple action menus, describe the whole thing as an items array — built on the same parts, the way Autocomplete is built on Combobox. Each item's onClick fires on activation (click and keyboard); a bare string is shorthand for { label, value }, { type: 'divider' } is a separator, and { group, items } is a section. A group takes an optional decorative prefix (the code-themed // leader, off by default; hidden from screen readers and the clipboard). The component is generic over const items, so an item's explicit value narrows the optional top-level onSelect(value).

Nothing selected yet

Code

<Menuitems={[  { label: 'Profile', value: 'profile', startSection: <User /> },  { label: 'Settings', value: 'settings', startSection: <Settings /> },  { type: 'divider' },  { group: 'Danger zone', prefix: '// ', items: [    { label: 'Delete', value: 'delete', color: 'red', startSection: <Trash2 /> },  ]},]}onSelect={(value) => setLast(value)} // value: 'profile' | 'settings' | 'delete'><Button variant="default" endSlot={<ChevronDown />}>Actions</Button></Menu>

Nest a Menu.Sub and open it from a Menu.SubTrigger; its dropdown is a Menu.SubContent (same surface as Menu.Content). In the data-driven form, an item with both a label and its own items becomes a submenu automatically.

Code

<Menu.Content><Menu.Item startSection={<Copy />}>Copy</Menu.Item><Menu.Item startSection={<Scissors />}>Cut</Menu.Item><Menu.Divider /><Menu.Sub>  <Menu.SubTrigger startSection={<Share2 />}>Share</Menu.SubTrigger>  <Menu.SubContent>    <Menu.Item startSection={<Link />}>Copy link</Menu.Item>    <Menu.Item startSection={<Mail />}>Email</Menu.Item>  </Menu.SubContent></Menu.Sub></Menu.Content>

Checkbox & radio

Menu.CheckboxItem and Menu.RadioGroup / Menu.RadioItem carry selection state. Set closeOnSelect={false} on Menu.Root to keep the dropdown open while toggling several options.

Code

<Menu.Root closeOnSelect={false}><Menu.Trigger asChild><Button variant="default" endSlot={<ChevronDown />}>View</Button></Menu.Trigger><Menu.Content>  <Menu.Label>Editor</Menu.Label>  <Menu.CheckboxItem value="wrap" checked={wrap} onCheckedChange={setWrap}>Word wrap</Menu.CheckboxItem>  <Menu.CheckboxItem value="minimap" checked={minimap} onCheckedChange={setMinimap}>Minimap</Menu.CheckboxItem>  <Menu.Divider />  <Menu.Label>Theme</Menu.Label>  <Menu.RadioGroup value={theme} onChange={setTheme}>    <Menu.RadioItem value="light">Light</Menu.RadioItem>    <Menu.RadioItem value="dark">Dark</Menu.RadioItem>    <Menu.RadioItem value="system">System</Menu.RadioItem>  </Menu.RadioGroup></Menu.Content></Menu.Root>

Context menu

Swap Menu.Trigger for Menu.ContextTrigger to open on right-click (and long-press on touch).

Code

<Menu.Root><Menu.ContextTrigger asChild>  <div>Right-click here</div></Menu.ContextTrigger><Menu.Content>  <Menu.Item startSection={<Copy />}>Copy</Menu.Item>  <Menu.Item startSection={<Scissors />}>Cut</Menu.Item>  <Menu.Divider />  <Menu.Item color="red" startSection={<Trash2 />}>Delete</Menu.Item></Menu.Content></Menu.Root>

Anatomy

  • Menu.Root — wraps Ark's Menu.Root; owns open state + positioning.
  • Menu.Trigger — the button that opens the menu; use asChild to wrap your own element. Menu.ContextTrigger opens on right-click instead.
  • Menu.Content — the portaled, animated dropdown.
  • Menu.Item — an action row, with startSection / endSection / color.
  • Menu.Label / Menu.Divider — a section heading and a separator. For ARIA-grouped sections use Menu.ItemGroup + Menu.ItemGroupLabel. Both headings accept an optional decorative prefix (e.g. "// ", off by default).
  • Menu.CheckboxItem, Menu.RadioGroup / Menu.RadioItem — stateful selection rows.
  • Menu.Sub / Menu.SubTrigger / Menu.SubContent — a nested submenu.

API

Menu.Root props (beyond Ark's Menu.Root):

Prop

Type

Menu.Item props (beyond Ark's Menu.Item):

Prop

Type

<Menu items> (data-driven) props:

Prop

Type

On this page