DropdownMenu
A menu of actions behind a button: the actions of a table row, a “More” menu. Its entries are
MenuItems of the menu variant, links or buttons.
import { DropdownMenu } from '@zitdevs/ui';Examples
Section titled “Examples”The demo is server HTML with no React on the page, which runs one script,
enhanceDropdownMenus(document) from @zitdevs/ui/enhance. Focus the button and press Enter: the
first entry takes focus. Move with the arrow keys, Home and End, or type the start of a name; the
disabled entry is skipped. Escape, or choosing an entry, closes the menu with focus back on the
button.
<DropdownMenu id="row-1-menu" label="Actions for Ada Lovelace" triggerLabel="Actions" align="end"> <MenuItem variant="menu" href="/people/1/edit" title="Edit" /> <MenuItem variant="menu" type="submit" form="end-1" title="End" /> <MenuItem variant="menu" title="Remove" disabled /></DropdownMenu>| Prop | Type | Default | Notes |
|---|---|---|---|
id |
string |
required | The list’s id; the button names it with popovertarget. The button’s is <id>-trigger. |
label |
string |
required | Names the menu and the button. Say whose actions: “Actions for Ada Lovelace”. |
triggerLabel |
string |
label |
The button’s visible text when shorter. It must be part of label (WCAG 2.5.3). |
align |
'start' | 'end' |
'start' |
The button’s edge the list lines up with. end for a button at the end of a row. |
children |
ReactNode |
required | The entries: MenuItem variant="menu". |
ref |
Ref<HTMLDivElement> |
— | The wrapper around the button and the list. |
| anything else | <div> attributes |
— |
Exported types: DropdownMenuProps. From @zitdevs/ui/enhance: enhanceDropdownMenus.
Accessibility
Section titled “Accessibility”- The button has
aria-haspopup="menu"andaria-expanded, which the enhancer keeps in step with the list; the list is arole="menu"named by the button. - Enter or Space opens it with focus on the first entry; ArrowDown opens at the first entry and ArrowUp at the last.
- In the menu: ArrowDown and ArrowUp move (wrapping), Home and End jump, and typing
the start of a name (or one letter, repeatedly) finds an entry. Entries that are
aria-disabledare skipped. - Escape and Tab close it and leave focus on the button; choosing an entry does the same, so focus is never lost with the list. A press outside closes it and leaves focus where it went.
- Every action is reachable from the keyboard; nothing exists only on hover.
Without JavaScript
Section titled “Without JavaScript”The button and the list are native: a popovertarget button opens a popover list, and the browser
closes it on Escape and on a press outside. The list opens beside the button, its entries in the tab
order, and every link and button works. Browsers older than 2024 lack popovers: show the actions
another way there. What the enhancer adds:
- focus in the first entry on open, and the arrow keys, Home, End and type-ahead;
aria-expandedon the button, and focus back on it when the menu closes;- the list placed under the button (or above it, or lined up with its end edge).
In React the menu’s small client part runs the enhancer once it has hydrated. Without React, call
enhanceDropdownMenus(document) once; it finds every [data-dropdown-menu].
Theming
Section titled “Theming”surface-raised and border-default for the list, shadow-lg for its lift, primary-soft for
the hovered entry, ink for text, the focus ring. Nothing is hard-coded.