Menu / Dropdown Menu
Preview: Actions
Menu in its own popover. Use inside MenuTrigger (after the trigger button) or SubmenuTrigger.
Import
import { Menu, MenuItem, MenuSection, MenuSeparator, MenuTrigger, SubmenuTrigger } from '@marbleui/ui'Props
<MenuItem>
| Prop | Type | Default | Description |
|---|---|---|---|
| destructive | boolean | — | |
| icon | ReactNode | — | |
| shortcut | string | — |
Also accepts React Aria props (100).
<MenuSeparator>
No props of its own.
<MenuTrigger>
Re-exported from React Aria MenuTrigger; see its documentation for props.
Accessibility
Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria Collection · React Aria Header · React Aria Menu · React Aria MenuItem · React Aria MenuSection · React Aria MenuTrigger · React Aria Separator · React Aria SubmenuTrigger. Follow the primitive's docs for the full keyboard map.
Usage notes
Actions in a popover list. Place Menu inside MenuTrigger, after the trigger.
<MenuTrigger>
<IconButton aria-label="More actions"><DotsIcon /></IconButton>
<Menu onAction={(key) => run(key)}>
<MenuItem id="rename">Rename</MenuItem>
<MenuItem id="delete" destructive>Delete</MenuItem>
</Menu>
</MenuTrigger>
- Use
onActionfor commands. For persistent choices useMenuSectionwithselectionMode(radio/checkbox semantics). - Nest with
SubmenuTrigger; typeahead and arrow keys work throughout. - For navigation lists use links, not menus.
Example source · show· hide
import { useState } from 'react'
import type { Selection } from 'react-aria-components'
import { Button } from '../button'
import { IconButton } from '../icon-button'
import { Menu, MenuItem, MenuSection, MenuSeparator, MenuTrigger, SubmenuTrigger } from './menu'
const I = ({ d }: { d: string }) => (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
<path d={d} />
</svg>
)
const icons = {
edit: 'M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z',
copy: 'M8 8h12v12H8zM4 16V4h12',
share: 'M4 12v8h16v-8M16 6l-4-4-4 4M12 2v13',
trash: 'M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6',
more: 'M12 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2M19 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2M5 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2',
}
function ViewMenu() {
const [sort, setSort] = useState<Selection>(new Set(['updated']))
const [show, setShow] = useState<Selection>(new Set(['assignee', 'labels']))
return (
<MenuTrigger>
<Button variant="outline">View options</Button>
<Menu>
<MenuSection title="Sort by" selectionMode="single" selectedKeys={sort} onSelectionChange={setSort}>
<MenuItem id="updated">Last updated</MenuItem>
<MenuItem id="created">Created</MenuItem>
<MenuItem id="priority">Priority</MenuItem>
</MenuSection>
<MenuSeparator />
<MenuSection title="Show" selectionMode="multiple" selectedKeys={show} onSelectionChange={setShow}>
<MenuItem id="assignee">Assignee</MenuItem>
<MenuItem id="labels">Labels</MenuItem>
<MenuItem id="estimate">Estimate</MenuItem>
</MenuSection>
</Menu>
</MenuTrigger>
)
}
export const styles = {
Actions: () => (
<MenuTrigger>
<IconButton variant="outline" aria-label="Actions"><I d={icons.more} /></IconButton>
<Menu>
<MenuItem icon={<I d={icons.edit} />} shortcut="E">Rename</MenuItem>
<MenuItem icon={<I d={icons.copy} />} shortcut="⌘D">Duplicate</MenuItem>
<SubmenuTrigger>
<MenuItem icon={<I d={icons.share} />}>Share</MenuItem>
<Menu>
<MenuItem>Copy link</MenuItem>
<MenuItem>Email</MenuItem>
<MenuItem>Slack</MenuItem>
</Menu>
</SubmenuTrigger>
<MenuSeparator />
<MenuItem icon={<I d={icons.trash} />} shortcut="⌫" destructive>Delete</MenuItem>
</Menu>
</MenuTrigger>
),
Selection: ViewMenu,
}Source: packages/ui/src/menu/menu.tsx
Catalog
- Category
- overlays
- Priority
- Foundation
- Primitive
- react-aria
- React Aria
- Menu + MenuTrigger + SubmenuTrigger
- Base UI
- Menu