Skip to the content
BooleanPress UI

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 button with aria-haspopup="menu", aria-expanded and aria-controls. The content is role="menu"; items are menuitem, menuitemcheckbox (with aria-checked) or menuitemradio. A submenu trigger has aria-haspopup="menu" and aria-expanded.
Labels
The trigger's text names the menu; an icon-only trigger needs aria-label. DropdownMenuLabel names 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

Keyboard
KeyBehaviour
EnterSpaceOn 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.
HomeEndMoves to the first or last item.
A–ZType-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).
EscapeCloses the menu and returns focus to the trigger.
TabDoes 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.

DropdownMenu props
PropTypeDefaultDescription
defaultOpenbooleanWhether it starts open, when it controls itself.
dir"ltr" | "rtl"
modalbooleanWhether 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.
openbooleanWhether it is open, when you control it. Pair it with onOpenChange.

DropdownMenuPortal

Renders Radix DropdownMenu.Portal and passes it every other prop.

DropdownMenuPortal props
PropTypeDefaultDescription
containerElement | DocumentFragment | nullSpecify a container element to portal the content into.
forceMounttrueUsed 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.

DropdownMenuTrigger props
PropTypeDefaultDescription
asChildbooleanRender 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.

DropdownMenuContent props
PropTypeDefaultDescription
align"center" | "start" | "end"Alignment along that side: start, center or end. center by default.
alignOffsetnumber
arrowPaddingnumber
asChildboolean
avoidCollisionsboolean
collisionBoundaryBoundary | Boundary[]
collisionPaddingnumber | Partial<Record<"left" | "right" | "top" | "bottom", number>>
forceMounttrueUsed to force mounting when more control is needed. Useful when controlling animation with React animation libraries.
hideWhenDetachedboolean
loopbooleanWhether 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.
sideOffsetnumber4Distance 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.

DropdownMenuGroup props
PropTypeDefaultDescription
asChildboolean

DropdownMenuLabel

Renders Radix DropdownMenu.Label and passes it every other prop.

DropdownMenuLabel props
PropTypeDefaultDescription
asChildboolean
insetbooleanIndent the label to line up with items that have a check or dot.

DropdownMenuItem

Renders Radix DropdownMenu.Item and passes it every other prop.

DropdownMenuItem props
PropTypeDefaultDescription
asChildbooleanRender the child element instead, with this part's behaviour and classes merged onto it.
disabledbooleanSkips the item and ignores clicks.
insetbooleanIndent 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.
textValuestringThe text type-ahead matches, when the content is not plain text.
variant"default" | "destructive"defaultdefault, or destructive for an action that removes something.

DropdownMenuCheckboxItem

Renders Radix DropdownMenu.CheckboxItem and passes it every other prop.

DropdownMenuCheckboxItem props
PropTypeDefaultDescription
asChildboolean
checkedboolean | "indeterminate"Whether it is checked: true, false or "indeterminate". Pair it with onCheckedChange.
disabledbooleanSkips 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.
textValuestring

DropdownMenuRadioGroup

Renders Radix DropdownMenu.RadioGroup and passes it every other prop.

DropdownMenuRadioGroup props
PropTypeDefaultDescription
asChildboolean
onValueChange((value: string) => void)Called with the value of the item that was chosen.
valuestringThe chosen item's value. Pair it with onValueChange.

DropdownMenuRadioItem

Renders Radix DropdownMenu.RadioItem and passes it every other prop.

DropdownMenuRadioItem props
PropTypeDefaultDescription
asChildboolean
disabledbooleanSkips the item and ignores clicks.
onSelect((event: Event) => void)Called when the item is chosen. Call event.preventDefault() to keep the menu open.
textValuestring
valuestringThe value this item stands for.

DropdownMenuSeparator

Renders Radix DropdownMenu.Separator and passes it every other prop.

DropdownMenuSeparator props
PropTypeDefaultDescription
asChildboolean

DropdownMenuShortcut

Renders a span and passes it every other prop.

DropdownMenuSub

Renders Radix DropdownMenu.Sub and passes it every other prop.

DropdownMenuSub props
PropTypeDefaultDescription
defaultOpenboolean
onOpenChange((open: boolean) => void)Called with true or false when it opens or closes.
openbooleanWhether the submenu is open, when you control it.

DropdownMenuSubTrigger

Renders Radix DropdownMenu.SubTrigger and passes it every other prop.

DropdownMenuSubTrigger props
PropTypeDefaultDescription
asChildboolean
disabledbooleanSkips the item and ignores clicks.
insetbooleanIndent the item to line up with items that have a check or dot.
textValuestring

DropdownMenuSubContent

Renders Radix DropdownMenu.SubContent and passes it every other prop.

DropdownMenuSubContent props
PropTypeDefaultDescription
align"start" | "end"Controls the direction the subcontent appears from its anchor menu item Default: start
alignOffsetnumber
arrowPaddingnumber
asChildboolean
avoidCollisionsboolean
collisionBoundaryBoundary | Boundary[]
collisionPaddingnumber | Partial<Record<"left" | "right" | "top" | "bottom", number>>
forceMounttrueUsed to force mounting when more control is needed. Useful when controlling animation with React animation libraries.
hideWhenDetachedboolean
loopbooleanWhether keyboard navigation should loop around
onEscapeKeyDown((event: KeyboardEvent) => void)
onFocusOutside((event: FocusOutsideEvent) => void)
onInteractOutside((event: FocusOutsideEvent | PointerDownOutsideEvent) => void)
onPointerDownOutside((event: PointerDownOutsideEvent) => void)
sideOffsetnumber4Distance 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.

Theme tokens
TokenUsed for
--accentbackground
--accent-foregroundtext
--borderbackground
--destructivetext, background
--muted-foregroundtext
--popoverbackground
--popover-foregroundtext