Dropdown Menu

A contextual menu that opens on trigger. Built on Radix DropdownMenu for keyboard navigation, focus management, and a11y; animated with interruptible enter/exit transitions.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add dropdown-menu

Usage#

usage.tsxTSX
import {  DropdownMenu, DropdownMenuTrigger, DropdownMenuContent,  DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator,  DropdownMenuShortcut,} from "@/components/ui/dropdown-menu"import { Button } from "@/components/ui/button"import { Gear, SignOut, UserCircle } from "@phosphor-icons/react"export function Example() {  return (    <DropdownMenu>      <DropdownMenuTrigger asChild>        <Button variant="outline">My account</Button>      </DropdownMenuTrigger>      <DropdownMenuContent className="w-48">        <DropdownMenuLabel>My account</DropdownMenuLabel>        <DropdownMenuSeparator />        <DropdownMenuItem>          <UserCircle /> Profile          <DropdownMenuShortcut>⌘P</DropdownMenuShortcut>        </DropdownMenuItem>        <DropdownMenuItem>          <Gear /> Settings          <DropdownMenuShortcut>⌘,</DropdownMenuShortcut>        </DropdownMenuItem>        <DropdownMenuSeparator />        <DropdownMenuItem variant="destructive">          <SignOut /> Log out        </DropdownMenuItem>      </DropdownMenuContent>    </DropdownMenu>  )}

Avatar trigger#

Any element can be the trigger via asChild. A common pattern is a header avatar that opens an account menu, with the signed-in identity repeated as a non-interactive label at the top.

Icon button trigger#

A ghost iconOnly button makes a compact “more actions” menu for table rows and card headers. Align the content to the trigger edge with align="end".

Keyboard shortcuts#

DropdownMenuShortcut renders right-aligned monospaced text - purely decorative; wire up the actual key binding in your app with a global listener.

Checkbox items#

Switch items#

For a setting that applies the moment it flips, pass variant="switch" to a checkbox item. The row draws a switch on the same line as the shortcut and the check, and the menu stays open when it is toggled (closeOnSelect is off for switches), so several can be set in one visit. The row is still a menu checkbox with its checked state announced; the switch is its drawing, not a second control.

A row that navigates stays a menu item: wrap the link with asChild, so it keeps the row’s styling, arrow-key focus and Enter to activate, while Next.js client navigation and Cmd/Ctrl-click keep working. Mark a link that leaves the site with a trailing ArrowUpRight at size-4.

Descriptions#

A navigation menu often needs more than a label: a title over a sentence that says where the row goes. Put both in a DropdownMenuItemText after the leading icon, the sentence in a DropdownMenuItemDescription. A described row pins its icon to the title’s line instead of centering it on the block, and the sentence steps back by color and weight at the same size, so the title keeps the hierarchy. Give the content a wider measure (w-80) so the sentences wrap readably. Both parts are optional: a row without them stays a plain item.

Radio items#

By default a sub-menu is nested: it flies out beside its row. Pass submenu="navigation" and it drills in place instead: its rows replace the menu's behind a Back row, and the surface resizes to fit. Use it for a deep menu, or one with no room beside it. The parts and the rows are the same, and so are the keys: → goes in, and ← or Esc steps back one layer before the menu closes. It is the Dock's panel, opened from a trigger.

FAQ#

Use DropdownMenu for a list of actions or commands fired from a trigger, like a row's more-actions menu or an account menu. Reach for Select when the user is choosing a value to submit in a form; the menu's items run callbacks rather than holding a form value.