Dropdown Menu
A menu of actions revealed by clicking a button, per the WAI-ARIA Menu Button pattern — a ContextMenu opened by click and anchored to its trigger.
Usage#
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "neelam-ui";
<DropdownMenu>
<DropdownMenuTrigger>Actions</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>Project</DropdownMenuLabel>
<DropdownMenuItem>Rename</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>Built on ContextMenu#
A dropdown menu is a ContextMenu with a
different way in: clicking a real button instead of right-clicking, and
positioned against that button instead of at the cursor. Everything about the
panel — the native popover, its deferred opening, roving keyboard focus, scroll
lock, light dismissal — is identical, so it is built directly on ContextMenu
rather than duplicated. DropdownMenuContent, DropdownMenuItem,
DropdownMenuSeparator, DropdownMenuLabel, and DropdownMenuShortcut are the
same components under menu-flavoured names.
Only DropdownMenuTrigger is genuinely new.
Side#
side picks which side of the trigger the menu opens on — "bottom" by
default. "top" is for a trigger near the bottom of the viewport, such as an
account menu in a sidebar footer: opening below would run off-screen, and once
the viewport clamp caught that, the panel would land pinned to the bottom of the
viewport rather than next to its trigger.
<DropdownMenuTrigger side="top">Account</DropdownMenuTrigger>Menu, select, or popover?#
- Dropdown menu — a list of actions. Activating one does something and closes the menu.
Select— a list of values. One stays chosen, and the trigger shows it.Popover— arbitrary content the user works through, not a list at all.
Choosing wrongly here is not cosmetic: the roles differ (menu/menuitem
versus listbox/option), and so does what a screen reader tells the user to
expect.
Items#
DropdownMenuItem closes the menu after activating by default. Pass
closeOnSelect={false} for an item that toggles something the user may want to
change again straight away.
DropdownMenuShortcut renders a muted, right-aligned hint — place it as the
last child of an item. It is a label for a shortcut you have bound yourself; it
does not bind anything.
Keyboard#
| Key | Behaviour |
|---|---|
| EnterSpace | Opens the menu from the trigger, or activates the focused item. |
| ↓ | Opens the menu with the first item focused, without needing it open already. |
| ↑ | Opens the menu with the last item focused. |
| HomeEnd | Moves to the first or last item. |
| Escape | Closes the menu and returns focus to the trigger. |
The ArrowDown/ArrowUp mapping stays fixed to the key, not to side — it is
about where focus lands, not which way the menu opened.
Accessibility#
- The trigger is a native
<button>witharia-haspopup="menu"andaria-expanded, per the Menu Button pattern. - The panel is
role="menu"; each item is a native<button>recategorized asrole="menuitem", so click,Enter, andSpaceactivation stay native. - Roving focus: arrow keys move real DOM focus between items, wrapping at the ends. Disabled items are skipped.
DropdownMenuSeparatorisrole="separator"witharia-orientation, whichrole="menu"does permit — unlikerole="listbox", which is whySelect's separator carries no role at all.- Focus returns to the trigger on every dismissal path, and the page behind is scroll-locked while the menu is open.
API reference#
DropdownMenu#
| Prop | Type | Default |
|---|---|---|
onOpenChange | ((open: boolean) => void) | — |
openControls the open state. Omit to let the menu manage its own state. | boolean | — |
DropdownMenuTrigger#
| Prop | Type | Default |
|---|---|---|
sideWhich side of the trigger the menu opens on. Defaults to `"bottom"`. `"top"` is for a trigger that sits near the bottom of the viewport (a sidebar footer's account menu, say) — opening below there would either run off-screen or, once `DropdownMenuContent`'s own clamp caught that, land pinned to the bottom of the *viewport* rather than actually next to the trigger. | enum | bottom |
DropdownMenuItem#
| Prop | Type | Default |
|---|---|---|
closeOnSelectCloses the menu after this item is activated. Defaults to `true`. | boolean | — |
variant | "default" | "destructive" | null | — |