Menu
Dropdown menu
A list of actions that opens from a button, such as the actions of a table row.
Import
import { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent } from "@booleanpress/ui/dropdown-menu"Usage
A dropdown menu is for commands, not navigation between options of a form (use a select for that). The trigger is a button; choosing an item runs its onSelect and closes the menu.
import { Button } from "@booleanpress/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@booleanpress/ui/dropdown-menu"
export function MailerActions() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Actions</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem onSelect={() => duplicate()}>Duplicate</DropdownMenuItem>
<DropdownMenuItem variant="destructive" onSelect={() => remove()}>Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}DropdownMenuCheckboxItem toggles a setting and DropdownMenuRadioItem (inside DropdownMenuRadioGroup) chooses one of several; both stay in step with checked, or value and onValueChange. DropdownMenuSub nests a menu under a DropdownMenuSubTrigger. DropdownMenuLabel, DropdownMenuSeparator and DropdownMenuGroup organise items, and DropdownMenuShortcut shows a key hint without binding the key. An icon-only trigger needs aria-label. For a destructive action that cannot be undone, make the item open an alert dialog.
Examples
Actions
A row's actions, with a label, a group and a disabled item.
Checkbox items
Show or hide columns. Each choice closes the menu, unless onSelect calls event.preventDefault().
Radio items
Choose one of several values, with the chosen one marked.
Submenu
DropdownMenuSub opens a second list with → (← in right-to-left pages).
Destructive item
variant="destructive" colours an item that removes something.
With shortcuts
DropdownMenuShortcut shows the key hint at the end of the row.
Accessibility
- Semantics
- The trigger is a
buttonwitharia-haspopup="menu",aria-expandedandaria-controls. The content isrole="menu"; items aremenuitem,menuitemcheckbox(witharia-checked) ormenuitemradio. A submenu trigger hasaria-haspopup="menu"andaria-expanded. - Labels
- The trigger's text names the menu; an icon-only trigger needs
aria-label.DropdownMenuLabelnames a section visually. Items are named by their text. - Focus
- Focus moves to the menu when it opens (to the first item when opened with the keyboard) and returns to the trigger when it closes. The menu is modal: the page behind it cannot be reached.
- Known limits
- Only text and icons in items. A menu is not a place for form controls: use a popover.
- A disabled item stays in the list and is announced as unavailable; the arrow keys skip it.
Keyboard
| Key | Behaviour |
|---|---|
| EnterSpace | On the trigger, opens the menu and highlights its first item. On an item, chooses it. |
| ↓ | On the trigger, opens the menu. In the menu, moves to the next item, wrapping at the end. |
| ↑ | In the menu, moves to the previous item, wrapping at the start. |
| HomeEnd | Moves to the first or last item. |
| A–Z | Type-ahead: moves to the next item whose text starts with the letters typed. |
| → | On a submenu trigger, opens its submenu (← in right-to-left pages). |
| ← | In a submenu, closes it and returns to its trigger (→ in right-to-left pages). |
| Escape | Closes the menu and returns focus to the trigger. |
| Tab | Does nothing while the menu is open: focus stays in the menu until it closes. |
API
DropdownMenu
Renders Radix DropdownMenu.Root and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | Whether it starts open, when it controls itself. | |
dir | "ltr" | "rtl" | ||
modal | boolean | Whether the rest of the page is blocked while it is open. true by default. | |
onOpenChange | ((open: boolean) => void) | Called with true or false when it opens or closes. | |
open | boolean | Whether it is open, when you control it. Pair it with onOpenChange. |
DropdownMenuPortal
Renders Radix DropdownMenu.Portal and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
container | Element | DocumentFragment | null | Specify a container element to portal the content into. | |
forceMount | true | Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. |
DropdownMenuTrigger
Renders Radix DropdownMenu.Trigger and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. |
DropdownMenuContent
Renders Radix DropdownMenu.Content and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
align | "center" | "start" | "end" | Alignment along that side: start, center or end. center by default. | |
alignOffset | number | ||
arrowPadding | number | ||
asChild | boolean | ||
avoidCollisions | boolean | ||
collisionBoundary | Boundary | Boundary[] | ||
collisionPadding | number | Partial<Record<"left" | "right" | "top" | "bottom", number>> | ||
forceMount | true | Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. | |
hideWhenDetached | boolean | ||
loop | boolean | Whether keyboard navigation should loop around | |
onCloseAutoFocus | ((event: Event) => void) | Event handler called when auto-focusing on close. Can be prevented. | |
onEscapeKeyDown | ((event: KeyboardEvent) => void) | Called when Escape is pressed. Call event.preventDefault() to keep it open. | |
onFocusOutside | ((event: FocusOutsideEvent) => void) | ||
onInteractOutside | ((event: FocusOutsideEvent | PointerDownOutsideEvent) => void) | ||
onPointerDownOutside | ((event: PointerDownOutsideEvent) => void) | ||
side | "left" | "right" | "top" | "bottom" | The preferred side: top, right, bottom or left. bottom by default; it flips when there is no room. | |
sideOffset | number | 4 | Distance in pixels from the trigger. 4 by default. |
sticky | "partial" | "always" | ||
updatePositionStrategy | "always" | "optimized" |
DropdownMenuGroup
Renders Radix DropdownMenu.Group and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean |
DropdownMenuLabel
Renders Radix DropdownMenu.Label and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
inset | boolean | Indent the label to line up with items that have a check or dot. |
DropdownMenuItem
Renders Radix DropdownMenu.Item and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. | |
disabled | boolean | Skips the item and ignores clicks. | |
inset | boolean | Indent the item to line up with items that have a check or dot. | |
onSelect | ((event: Event) => void) | Called when the item is chosen. Call event.preventDefault() to keep the menu open. | |
textValue | string | The text type-ahead matches, when the content is not plain text. | |
variant | "default" | "destructive" | default | default, or destructive for an action that removes something. |
DropdownMenuCheckboxItem
Renders Radix DropdownMenu.CheckboxItem and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
checked | boolean | "indeterminate" | Whether it is checked: true, false or "indeterminate". Pair it with onCheckedChange. | |
disabled | boolean | Skips the item and ignores clicks. | |
onCheckedChange | ((checked: boolean) => void) | Called with the new state when it is chosen. | |
onSelect | ((event: Event) => void) | Called when the item is chosen. Call event.preventDefault() to keep the menu open. | |
textValue | string |
DropdownMenuRadioGroup
Renders Radix DropdownMenu.RadioGroup and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
onValueChange | ((value: string) => void) | Called with the value of the item that was chosen. | |
value | string | The chosen item's value. Pair it with onValueChange. |
DropdownMenuRadioItem
Renders Radix DropdownMenu.RadioItem and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
disabled | boolean | Skips the item and ignores clicks. | |
onSelect | ((event: Event) => void) | Called when the item is chosen. Call event.preventDefault() to keep the menu open. | |
textValue | string | ||
value | string | The value this item stands for. |
DropdownMenuSeparator
Renders Radix DropdownMenu.Separator and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean |
DropdownMenuShortcut
Renders a span and passes it every other prop.
DropdownMenuSub
Renders Radix DropdownMenu.Sub and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | ||
onOpenChange | ((open: boolean) => void) | Called with true or false when it opens or closes. | |
open | boolean | Whether the submenu is open, when you control it. |
DropdownMenuSubTrigger
Renders Radix DropdownMenu.SubTrigger and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
disabled | boolean | Skips the item and ignores clicks. | |
inset | boolean | Indent the item to line up with items that have a check or dot. | |
textValue | string |
DropdownMenuSubContent
Renders Radix DropdownMenu.SubContent and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
align | "start" | "end" | Controls the direction the subcontent appears from its anchor menu item Default: start | |
alignOffset | number | ||
arrowPadding | number | ||
asChild | boolean | ||
avoidCollisions | boolean | ||
collisionBoundary | Boundary | Boundary[] | ||
collisionPadding | number | Partial<Record<"left" | "right" | "top" | "bottom", number>> | ||
forceMount | true | Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. | |
hideWhenDetached | boolean | ||
loop | boolean | Whether keyboard navigation should loop around | |
onEscapeKeyDown | ((event: KeyboardEvent) => void) | ||
onFocusOutside | ((event: FocusOutsideEvent) => void) | ||
onInteractOutside | ((event: FocusOutsideEvent | PointerDownOutsideEvent) => void) | ||
onPointerDownOutside | ((event: PointerDownOutsideEvent) => void) | ||
sideOffset | number | 4 | Distance in pixels from its trigger. |
sticky | "partial" | "always" | ||
updatePositionStrategy | "always" | "optimized" |
Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.
Data attributes: data-slot="dropdown-menu" (DropdownMenu), data-slot="dropdown-menu-portal" (DropdownMenuPortal), data-slot="dropdown-menu-trigger" (DropdownMenuTrigger), data-slot="dropdown-menu-content" (DropdownMenuContent), data-slot="dropdown-menu-group" (DropdownMenuGroup), data-slot="dropdown-menu-label" (DropdownMenuLabel), data-slot="dropdown-menu-item" (DropdownMenuItem), data-slot="dropdown-menu-checkbox-item" (DropdownMenuCheckboxItem), data-slot="dropdown-menu-radio-group" (DropdownMenuRadioGroup), data-slot="dropdown-menu-radio-item" (DropdownMenuRadioItem), data-slot="dropdown-menu-separator" (DropdownMenuSeparator), data-slot="dropdown-menu-shortcut" (DropdownMenuShortcut), data-slot="dropdown-menu-sub" (DropdownMenuSub), data-slot="dropdown-menu-sub-trigger" (DropdownMenuSubTrigger), data-slot="dropdown-menu-sub-content" (DropdownMenuSubContent), and data-inset, data-variant.
Theming
The menu is a floating surface: --popover and --popover-foreground. The highlighted item uses --accent; a destructive item uses --destructive.
The tokens its classes read. Change their values in your theme, and it follows.
| Token | Used for |
|---|---|
--accent | background |
--accent-foreground | text |
--border | background |
--destructive | text, background |
--muted-foreground | text |
--popover | background |
--popover-foreground | text |