DropdownMenu
OrganismAccessible dropdown using role="menu" + role="menuitem". Closes on Escape and outside click. Supports left/right alignment, icons, separators, danger and disabled items, and arrow-key navigation. Items take an optional id, href, group, order, hidden and disabledReason so other modules can contribute entries; `portal` escapes clipping parents.
<DropdownMenu
trigger={<Button variant="outline" size="sm">Actions ▾</Button>}
items={[
{ label: 'Edit', icon: '✏' },
{ label: 'Duplicate', icon: '⧉' },
{ type: 'separator' },
{ label: 'Delete', icon: '🗑', danger: true },
]}
/><DropdownMenu align="right"
trigger={<Button variant="ghost" size="sm">⋮</Button>}
items={[{ label: 'View details' }, { label: 'Remove', danger: true }]}
/>// Items sort by group (ranked by their lowest order) and order; a separator splits groups.
<DropdownMenu
trigger={<Button variant="outline" size="sm">Contact ▾</Button>}
items={[
{ id: 'edit', label: 'Edit', group: 'record', order: 10 },
{ id: 'call', label: 'Call', group: 'contact', order: 20, href: '/calls/new?to=…' },
{ id: 'sign', label: 'Send for signature', group: 'contact', order: 30, disabled: true, disabledReason: 'Add an email address first' },
{ id: 'campaign', label: 'Add to campaign', group: 'contact', order: 40, hidden: !canMarket },
{ id: 'delete', label: 'Delete', group: 'danger', order: 1000, danger: true },
]}
/>
// Merge contributed items into a base list (same id replaces in place):
const items = mergeMenuItems(baseItems, contributedItems);