Dropdown Menu
A menu of actions opened from a button: icons, shortcuts, check and radio items, submenus.
Installation
npx @yolkui/cli add dropdown-menuUsage
Pass the control the trigger should look like through render: render={<Button variant="outline" />}. The menu opens 6px below it, its start edge on the trigger's, at least as wide as the trigger, and the trigger keeps its hover fill while the menu is open. An icon goes first in an item and takes the muted colour; DropdownMenuShortcut goes last, in muted text ("⇧⌘P", "Ctrl+K", "F2"). A DropdownMenuSub opens beside its row, its first item level with it. variant="destructive" turns an item's text and icon red; put it last, after a separator. inset on an item, label or sub-trigger without an icon lines its text up with the rows that have one.
- A menu holds actions. To pick a value for a form, use Select; to switch views, Tabs or a SegmentedControl.
Checkbox and radio items
DropdownMenuCheckboxItem turns a setting on or off and the menu stays open, so several can be changed in a row; DropdownMenuRadioItem in a DropdownMenuRadioGroup picks one. The check and the dot sit in a column at the start of the row, as in macOS and Windows menus, so the state reads first and the checks line up; give a label or a plain item beside them inset, so its text starts on the same line. A DropdownMenuLabel inside a group names it for screen readers.
Disabled
A disabled item fades and does nothing, but the arrow keys still reach it, so a keyboard user learns it exists. Say why in the item's text when it is short ("Team (Business plan)").
Links
An item that goes to a page is a DropdownMenuLinkItem: a real link, so Cmd/Ctrl-click, a middle click and "Open in new tab" work, which an item with onClick cannot do. It looks like any item and closes the menu when clicked. With a router, render its link: render={<Link href="/docs/cli" />}. Keep DropdownMenuItem for actions that stay on the page.
In a toolbar
Render ToolbarButton as the trigger: it stays in the toolbar's arrow-key order, and Enter, Space or ArrowDown opens the menu. At the end of a bar, align="end" keeps the menu under it.
Accessibility
The trigger is a button with aria-haspopup and aria-expanded; the popup is a menu of menuitems, menuitemcheckboxes and menuitemradios. Enter, Space or ArrowDown open it on the first item, ArrowUp on the last; the arrows move, Home and End go to the ends, typing jumps to an item, ArrowRight opens a submenu and ArrowLeft closes it. Escape closes the menu and returns focus to the trigger; Tab closes it and moves on.
- An icon-only trigger needs aria-label.
- The shortcut text is hidden from screen readers; the item carries them as aria-keyshortcuts ("Meta+D") instead, so "Duplicate" is not read as "Duplicate command D".
- Shortcuts shown in a menu are a promise: wire the keys themselves in your app.
- Show the keys of the platform the reader is on: ⌘ exists only on a Mac. Pass the text for each, e.g. isMac ? "⌘D" : "Ctrl+D" (isMac from /Mac|iPhone|iPad/.test(navigator.platform), read after mount), as VS Code and Linear do. aria-keyshortcuts follows the text.