Skip to content

Documentation

neelam-ui

Search documentation

Getting Started
Forms
Overlays
Navigation
Data Display
Layout
AI & Chat
Blocks
GitHub repository

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>
  • 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#

Keyboard shortcuts
KeyBehaviour
EnterSpaceOpens 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.
HomeEndMoves to the first or last item.
EscapeCloses 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> with aria-haspopup="menu" and aria-expanded, per the Menu Button pattern.
  • The panel is role="menu"; each item is a native <button> recategorized as role="menuitem", so click, Enter, and Space activation stay native.
  • Roving focus: arrow keys move real DOM focus between items, wrapping at the ends. Disabled items are skipped.
  • DropdownMenuSeparator is role="separator" with aria-orientation, which role="menu" does permit — unlike role="listbox", which is why Select'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#

Props for DropdownMenu
PropTypeDefault
onOpenChange((open: boolean) => void)
open

Controls the open state. Omit to let the menu manage its own state.

boolean
Props for DropdownMenuTrigger
PropTypeDefault
side

Which 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.

enumbottom
Props for DropdownMenuItem
PropTypeDefault
closeOnSelect

Closes the menu after this item is activated. Defaults to `true`.

boolean
variant"default" | "destructive" | null