DropdownMenu
A trigger button that opens a floating menu of actions with arrow-key navigation, typeahead, separators, and disabled items.
Installation
npx dafink-ui add dropdown-menuDemo
Props
| Name | Type | Default | Description |
|---|---|---|---|
| items | DropdownMenuEntry[] | - | Array of items ({ label, onSelect?, disabled? }) and separators ({ separator: true }). |
| trigger | ReactNode | - | Content of the built-in trigger button. |
| side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | Which side of the trigger the menu appears on. |
| align | 'start' | 'center' | 'end' | 'start' | Alignment along the chosen side. |
| onSelect | (item: DropdownMenuItem) => void | undefined | Called with the activated item, in addition to the item's own onSelect. |
| disabled | boolean | false | Disables the trigger. |
| className | string | '' | Additional classes on the menu list. |
| triggerClassName | string | '' | Additional classes on the trigger button. |
Accessibility
DropdownMenu uses virtual focus, not roving tabindex: the menu list itself takes DOM focus (tabIndex={-1}) on open, and the highlighted item is tracked purely via aria-activedescendant rather than moving real DOM focus between <li role="menuitem"> items. It is a non-modal popup: Tab is never trapped, it closes the menu and continues to the next page element. The trigger carries aria-haspopup="menu"/aria-expanded/aria-controls; the list is role="menu"; separators are role="separator".
| Key | Function |
|---|---|
| enter | On trigger: opens the menu. In the menu: activates the active item and closes. |
| space | Same as Enter. |
| down arrow | On trigger: opens with the first item active. In the menu: moves to the next enabled item, wrapping. |
| up arrow | On trigger: opens with the last item active. In the menu: moves to the previous enabled item, wrapping. |
| home | Moves to the first enabled item. |
| end | Moves to the last enabled item. |
| escape | Closes the menu and returns focus to the trigger. |
| tab | Closes the menu without intercepting the keypress, so focus continues to the next page element. |