Manual UI Templates DropdownMenu

DropdownMenu

elements man ui/templates/dropdown-menu

A menu of actions from a button, with submenus, checkbox and radio items.

Example
import { DropdownMenu, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuGroup, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, } from "@elements/ui/dropdown-menu"; import { Button } from "@elements/ui/button"; <DropdownMenu> <Button slot="trigger">Open</Button> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuItem onSelect={() => go("/profile")}> Profile <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut> </DropdownMenuItem> <DropdownMenuSeparator /> <DropdownMenuCheckboxItem checked={view.statusBar}>Status bar</DropdownMenuCheckboxItem> <DropdownMenuRadioGroup value={view.position}> <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem> <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem> </DropdownMenuRadioGroup> <DropdownMenuSub label="More tools"> <DropdownMenuItem>Save page as</DropdownMenuItem> </DropdownMenuSub> </DropdownMenu>

Parts

Part What it is
DropdownMenu The root: owns open, renders the trigger slot and, while open, the floating role=menu content with the default slot's items.
DropdownMenuItem An action row (role=menuitem). With href it renders a link. Selecting it closes the menu unless onSelect calls preventDefault() or closeOnSelect is false.
DropdownMenuCheckboxItem A row that toggles (role=menuitemcheckbox). checked is two-way and may be "indeterminate".
DropdownMenuRadioGroup Groups radio items (role=group); value is two-way and holds the checked item's value.
DropdownMenuRadioItem One choice in a radio group (role=menuitemradio).
DropdownMenuLabel A heading row. Skipped by arrow keys; names the group it sits in.
DropdownMenuGroup Groups items (role=group).
DropdownMenuSeparator A rule between groups (role=separator).
DropdownMenuShortcut A keyboard hint at the end of an item.
DropdownMenuSub A submenu: renders its trigger row (label or the trigger slot) and, while open, its own floating menu with the default slot's items.
DropdownMenuInput A filter row at the top of the menu: typing hides the rows that do not match. Focus stays in the input while ArrowDown and ArrowUp move the highlight; Enter chooses.
DropdownMenuClear A button that empties the filter input. clearButton on the input renders one in its row.
DropdownMenuEmpty A row shown only when the filter matches nothing. Its default slot is the message.

Slots

Slot Part Content
trigger DropdownMenu The button that opens the menu, usually a <Button>. It gets aria-haspopup=menu, aria-expanded, aria-controls, an id and data-state.
default DropdownMenu The menu's items, labels, groups, separators and submenus.
default DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioItem The row: text, an <Icon> (sized from --icon-size), a Shortcut.
indicator DropdownMenuCheckboxItem, DropdownMenuRadioItem Replaces the check (or dot) shown while checked. Put the checked glyph in an element with class is-checked, the indeterminate one in is-indeterminate.
trigger DropdownMenuSub Rich content for the trigger row (an icon and text); label is the plain-text form.
default DropdownMenuSub The submenu's items.

Keyboard

Keys Action
Enter / Space On the trigger: opens the menu and focuses the first item (closes it when open).
ArrowDown On the trigger: opens the menu and focuses the first item.
ArrowUp On the trigger: opens the menu and focuses the last item.
ArrowDown / ArrowUp Next or previous item; from the menu itself, the first or last. Wraps with loop.
Home / PageUp First item.
End / PageDown Last item.
Enter / Space Chooses the item (toggles a checkbox, checks a radio) and closes the menu; on a sub trigger, opens the submenu and focuses its first item.
ArrowRight (ArrowLeft in rtl) On a sub trigger, opens the submenu and focuses its first item.
ArrowLeft (ArrowRight in rtl) In a submenu, closes it and focuses its trigger.
A letter Typeahead: focuses the next enabled item that starts with the typed text.
Escape Closes the whole menu and returns focus.
Tab / Shift + Tab Closes the menu and moves focus on, as from the trigger.
ArrowDown / ArrowUp, Enter (in a filter input) Move the highlight while focus stays in the input; Enter chooses the highlighted row.

Data attributes

Attribute Values On Description
data-state "open" | "closed" trigger
data-pressed present trigger While the menu a press of the trigger opened is open (not a hover).
data-state, data-starting-style, data-ending-style "open" | "closed" .menu-backdrop With backdrop; follows the content.
data-disabled present trigger While disabled.
data-activation-direction "left" | "right" | "up" | "down", one per axis .dropdown-menu (content) After moving to another trigger: which way it lies.
data-morphing present .dropdown-menu (content) While the popup moves and resizes to another trigger.
data-state "open" | "closed" .dropdown-menu (content)
data-side "top" | "right" | "bottom" | "left" .dropdown-menu (content) The side it opened on, after flipping.
data-align "start" | "center" | "end" .dropdown-menu (content)
data-orientation "vertical" .dropdown-menu (content), items
data-highlighted present DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioItem, sub trigger The focused row, by keyboard or pointer.
data-disabled present items
data-variant "default" | "destructive" DropdownMenuItem
data-state "checked" | "unchecked" | "indeterminate" DropdownMenuCheckboxItem, DropdownMenuRadioItem, .menu-item-indicator
data-state "open" | "closed" sub trigger (.menu-sub-trigger)
data-orientation "horizontal" | "vertical" DropdownMenuSeparator
hidden present items, groups, separators, empty row Set by the filter on rows that do not match.
data-instant "click" | "dismiss" | "group" .dropdown-menu (content), arrow, backdrop click when the keyboard opened it, dismiss when Escape closed it, group when a menubar swapped menus; a theme may skip the animation.
--positioner-width / --positioner-height px .dropdown-menu (content) The content places itself, so these are its own size while open.
data-highlighted present DropdownMenuInput While the input shows focus; cleared when the keyboard highlights a row.
data-starting-style, data-ending-style present .menu-item-indicator One frame as the indicator turns on; while it turns off (valued with the state it leaves) until its transitions end.

Accessibility

  • The trigger gets aria-haspopup=menu, aria-expanded and aria-controls (WAI-ARIA menu button). The menu opens on pointer down, so press, drag to an item and release chooses it in one gesture.
  • Opened from the keyboard, focus lands on the first (ArrowUp: last) item; opened with the pointer, on the menu itself. On close, focus returns to the trigger, except after Tab, or a press outside a non-modal menu.
  • modal hides the rest of the page from assistive tech with aria-hidden and blocks the pointer outside.
  • The content is role=menu, named by its trigger (aria-labelledby) unless label is set. Items are menuitem, menuitemcheckbox (aria-checked true, false or mixed) and menuitemradio; disabled rows carry aria-disabled.
  • Rows take real focus (tabindex=-1, roving) and the focused row carries data-highlighted, so screen readers follow the keyboard.
  • A sub trigger has aria-haspopup=menu, aria-expanded and aria-controls; its submenu sits right after it in the DOM, as APG asks.
  • A label row inside a group names the group (aria-labelledby).
  • Disabled rows stay focusable by keyboard (APG menus), so a screen reader user hears them; the pointer and typeahead skip them.
  • The content is popover=manual in the top layer: never clipped by an overflow or transform ancestor, no portal, no z-index.

See also