ComponentsOverlayDropdownMenu

DropdownMenu

Floating panel of actions triggered by a button. Supports checkbox, radio, search, avatar items and context menus.

MenuItemCheckboxRadioSearchContext menuDark theme

Overview

Floating panel of actions triggered by a button. Supports checkbox, radio, search, avatar items and context menus.

Action menu

Live preview

Group secondary record actions behind one clearly labelled trigger.

ActionMenu.tsx
tsx
import { DropdownMenu, MenuItem, MenuSeparator, Button } from 'omverse-ui'
 
<DropdownMenu trigger={<Button variant="outlined">Actions</Button>}>
<MenuItem icon="edit" shortcut="⌘E">Edit</MenuItem>
<MenuItem icon="refresh">Duplicate</MenuItem>
<MenuItem icon="share">Share</MenuItem>
<MenuSeparator />
<MenuItem icon="trash" intent="danger">Delete</MenuItem>
</DropdownMenu>

Use a dropdown menu for related actions that do not all need persistent visibility. Keep the most important action outside the menu.

Anatomy

  • Root container and trigger area with popover boundary.
  • Menu content blocks grouped by sections and optional search controls.
  • Action rows with icons, shortcuts, and state indicators.
  • Context menu fallback surface for right-click or touch-hold use cases.
Diagram
tsx
Trigger ──► MenuPanel ──► {MenuItem, MenuSeparator, MenuGroup, MenuCheckboxItem, MenuRadioItem, MenuAvatarItem...}

When to use

  • Choose DropdownMenu for command surfaces that open from one control.
  • Use for dense action sets that need contextual visibility on demand.
  • Use in lists, cards, and toolbars where actions share the same context.

When not to use

  • Do not use only for decorative layout without interaction meaning.
  • Avoid when actions are always visible and must not be hidden.
  • Prefer tabs or segmented controls for primary navigation.

Variants

Common variants include icon-only triggers, dark theme, compact width control, and table/context-menu entry styles.

States

  • Idle, focus, open, disabled items, and checked/selected states.
  • Radio/checkbox states should preserve visual grouping and semantics.
  • Destructive actions should be clearly marked with intent styling.

Behavior

Keep keyboard order natural and predictable. Right-click actions should mirror pointer interactions where possible.

Accessibility

  • Use visible labels with sufficient contrast, especially in compact menus.
  • Preserve focus ring and keyboard navigation order.
  • Use intent="danger" and ARIA labels for destructive actions.

Content guidelines

  • Keep action labels concise and action-oriented.
  • Use similar phrasing across menus for consistency.
  • Limit nested content density so one menu remains easy to scan.

Examples

Basic

Live preview

Standard action list with icon, keyboard shortcut and a destructive delete item

App.tsx
tsx
import { DropdownMenu, MenuItem, MenuSeparator, Button } from 'omverse-ui'
 
<DropdownMenu trigger={<Button variant="outlined">Actions</Button>}>
<MenuItem icon="edit" shortcut="⌘E">Edit</MenuItem>
<MenuItem icon="refresh">Duplicate</MenuItem>
<MenuItem icon="share">Share</MenuItem>
<MenuSeparator />
<MenuItem icon="trash" intent="danger">Delete</MenuItem>
</DropdownMenu>

With groups

Live preview

MenuGroup organises items under a label — useful for settings and filter menus

App.tsx
tsx
import { DropdownMenu, MenuItem, MenuSeparator, MenuGroup, Button } from 'omverse-ui'
 
<DropdownMenu trigger={<Button variant="outlined">View options</Button>}>
<MenuGroup label="Layout">
<MenuItem icon="dots">Grid view</MenuItem>
<MenuItem icon="dots-vertical">List view</MenuItem>
</MenuGroup>
<MenuSeparator />
<MenuGroup label="Sort by">
<MenuItem>Name</MenuItem>
<MenuItem>Date modified</MenuItem>
<MenuItem>Size</MenuItem>
</MenuGroup>
</DropdownMenu>

Checkbox items

Live preview

MenuCheckboxItem shows a checked state and fires onCheckedChange

App.tsx
tsx
import { DropdownMenu, MenuCheckboxItem, Button } from 'omverse-ui'
 
const [sidebar, setSidebar] = useState(true);
const [toolbar, setToolbar] = useState(false);
const [statusbar, setStatusbar] = useState(true);
 
<DropdownMenu trigger={<Button variant="outlined">Toggle features</Button>}>
<MenuCheckboxItem checked={sidebar} onCheckedChange={setSidebar}>
Show sidebar
</MenuCheckboxItem>
<MenuCheckboxItem checked={toolbar} onCheckedChange={setToolbar}>
Show toolbar
</MenuCheckboxItem>
<MenuCheckboxItem checked={statusbar} onCheckedChange={setStatusbar}>
Show statusbar
</MenuCheckboxItem>
</DropdownMenu>

Dark theme

Live preview

theme='dark' gives the menu panel a dark background

App.tsx
tsx
<DropdownMenu trigger={<Button variant="filled">Dark menu</Button>} theme="dark">
<MenuItem icon="edit">Edit</MenuItem>
<MenuItem icon="refresh">Duplicate</MenuItem>
<MenuSeparator />
<MenuItem icon="trash" intent="danger">Delete</MenuItem>
</DropdownMenu>

Context menu — right click

Live preview

ContextMenu wraps any element and shows a menu on right-click

Right-click anywhere here
App.tsx
tsx
import { ContextMenu, MenuItem, MenuSeparator } from 'omverse-ui'
 
<ContextMenu
menu={
<>
<MenuItem icon="download" shortcut="⌘C">Copy</MenuItem>
<MenuItem icon="minus" shortcut="⌘X">Cut</MenuItem>
<MenuItem icon="bookmark" shortcut="⌘V">Paste</MenuItem>
<MenuSeparator />
<MenuItem icon="trash" intent="danger">Delete</MenuItem>
</>
}
>
<div style={{ border: '1px dashed var(--color-border)', borderRadius: 8, padding: '20px 40px' }}>
Right-click anywhere here
</div>
</ContextMenu>

Profile menu

Live preview

MenuHeader with search and action items

App.tsx
tsx
import { DropdownMenu, MenuHeader, MenuSearch, MenuItem, MenuSeparator, Button } from 'omverse-ui'
 
const [query, setQuery] = useState('');
 
<DropdownMenu trigger={<Button variant="outlined">Profile menu</Button>}>
<MenuHeader name="Jane Smith" email="jane@example.com" />
<MenuSeparator />
<MenuSearch value={query} onChange={setQuery} placeholder="Search..." />
<MenuItem icon="users">Profile</MenuItem>
<MenuItem icon="settings">Settings</MenuItem>
<MenuSeparator />
<MenuItem icon="arrow-right" intent="danger">Sign out</MenuItem>
</DropdownMenu>

Radio and avatar selection

Live preview

MenuRadioItem handles exclusive settings while MenuAvatarItem presents people pickers

App.tsx
tsx
import { DropdownMenu, MenuRadioItem, MenuAvatarItem, MenuSeparator, Button } from 'omverse-ui'
 
const [density, setDensity] = useState('comfortable');
const [owner, setOwner] = useState('Maya Chen');
 
<DropdownMenu trigger={<Button variant="outlined">Assignment</Button>} minWidth={260}>
<MenuRadioItem checked={density === 'compact'} onSelect={() => setDensity('compact')}>
Compact density
</MenuRadioItem>
<MenuRadioItem checked={density === 'comfortable'} onSelect={() => setDensity('comfortable')}>
Comfortable density
</MenuRadioItem>
<MenuSeparator />
<MenuAvatarItem name="Maya Chen" role="Design lead" selected={owner === 'Maya Chen'} onClick={() => setOwner('Maya Chen')} />
<MenuAvatarItem name="Alex Morgan" role="Engineering" selected={owner === 'Alex Morgan'} onClick={() => setOwner('Alex Morgan')} />
</DropdownMenu>

Color and reaction inputs

Live preview

MenuColorPicker and MenuEmojiReactions add rich inputs inside a menu

App.tsx
tsx
import { DropdownMenu, MenuColorPicker, MenuEmojiReactions, Button } from 'omverse-ui'
 
const [color, setColor] = useState('#6366f1');
 
<DropdownMenu trigger={<Button variant="outlined">Customize</Button>} minWidth={240}>
<MenuColorPicker value={color} onChange={setColor} />
<MenuEmojiReactions onReact={(emoji) => console.log(emoji)} />
</DropdownMenu>

Props / API

Api Props

Props

PropTypeDefaultDescription
triggerReactNode—Element that triggers the menu — usually a Button or IconButton
childrenReactNode—Menu content — use MenuItem, MenuSeparator, MenuGroup etc.
theme'light' | 'dark''light'Visual theme of the menu panel
align'start' | 'end' | 'center''start'Horizontal alignment relative to the trigger
side'bottom' | 'top''bottom'Which side of the trigger to open on
openbooleanundefinedControlled open state
onOpenChange(open: boolean) => voidundefinedCallback when open state changes
minWidthnumberundefinedMinimum width of the menu panel in px