For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt, and this page is available as Markdown at https://wallarm.github.io/design-system/components/dropdown-menu.md.

DropdownMenu

A menu of actions hanging off a trigger — reach for Select when the reader is choosing a value for a form, since a menu runs commands rather than holding an answer. Leave the primary action visible as a Button and put only the secondary ones in here; past roughly ten items, group them or move them somewhere with room.

Source · Storybook

Usage

import { Button } from '@wallarm-org/design-system/Button';
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, DropdownMenuTriggerItem } from '@wallarm-org/design-system/DropdownMenu';
import { Kbd, KbdGroup } from '@wallarm-org/design-system/Kbd';

Examples

Context

DropdownMenuContextTrigger opens the same menu on right-click, and DropdownMenuTriggerItem nests a submenu inside it. Always leave a left-click route to the same actions — a right-click-only affordance is undiscoverable.

With descriptions

DropdownMenuItemContent pairs DropdownMenuItemText with DropdownMenuItemDescription for a second line. Descriptions make a menu tall quickly, which is when separators start doing real work.

With icons

DropdownMenuItemIcon sits before the label. Icon every item in a group or none of them — a half-iconned list reads as though some items are missing theirs.

DropdownMenuFooter bleeds to the panel edge under a divider and renders at secondary emphasis, so it suits a persistent link or count rather than an action competing with the items.

With description and icons

Icons and descriptions together, which is the widest an item gets. Past this the menu is doing a panel's job — reach for a Popover.

With checkbox items

DropdownMenuCheckboxItem for options that aren't mutually exclusive. Selecting one leaves the menu open, so several can be toggled in a single visit.

With radio group

DropdownMenuRadioGroup for one-of-many. It also stays open on select, so the reader sees the indicator move before dismissing it themselves.

With mixed selection items

Commands, checkboxes and a radio group in one menu. DropdownMenuLabel and DropdownMenuSeparator are what keep the three kinds from reading as one flat list.

Props

PropTypeDefaultDescription
openboolean | undefined
defaultOpenboolean | undefined
onOpenChange((open: boolean) => void) | undefined
modalboolean | undefined
anchorPoint{ x: number; y: number; } | undefinedVirtual anchor point for positioning without a trigger element
positioningPositioningOptions | undefinedOverride default positioning config
highlightedValuestring | null | undefinedProgrammatically control which item is highlighted
onHighlightChange((details: HighlightChangeDetails) => void) | undefinedCallback when the highlighted item changes (e.g. on mouse hover)
closeOnSelectboolean | undefinedWhether selecting an item closes the menu (default true)
onRequestDismiss((event: LayerDismissEvent) => void) | undefinedCalled when another layer asks this menu to dismiss — e.g. a layer below it in the stack is removed. Call event.preventDefault() to keep the menu open.
idsElementIds | undefinedOverride the trigger element's id. Pass the same id to another compound component's ids.trigger (e.g. Tooltip, Popover) to compose their triggers on one element via nested asChild without an extra wrapper node — otherwise the outer trigger's id wins and the other component can't find its own anchor.
data-testidstring | undefined
PropTypeDefaultDescription
checked *boolean
onCheckedChange((checked: boolean) => void) | undefined
valuestring | undefinedOptional — auto-generated via useId() if omitted
disabledboolean | undefined
closeOnSelectboolean | undefined
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
variant{ default: string; brand: string; destructive: string; }default
inset{ true: string; }
data-testidstring | undefined
PropTypeDefaultDescription
asChildboolean | undefined
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
type"button" | "submit" | "reset" | undefined
disabledboolean | undefined
namestring | undefined
valuestring | number | readonly string[] | undefined
data-testidstring | undefined
PropTypeDefaultDescription
insetboolean | undefinedfalse
disabledboolean | undefined
onSelect(() => void) | undefined
valuestring | undefinedExplicit value for programmatic highlighting via highlightedValue
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
variant{ default: string; brand: string; destructive: string; }default
data-testidstring | undefined
PropTypeDefaultDescription
valuestring | undefined
onValueChange((details: { value: string; }) => void) | undefined
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
data-testidstring | undefined
PropTypeDefaultDescription
value *stringRequired — identifies this radio within the group
disabledboolean | undefined
closeOnSelectboolean | undefined
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
variant{ default: string; brand: string; destructive: string; }default
inset{ true: string; }
data-testidstring | undefined
PropTypeDefaultDescription
asChildboolean | undefined
valuestring | undefinedA real <button>'s value DOM property is always a string at runtime. Narrowed from the native ButtonHTMLAttributes['value'] (string | number | readonly string[] | undefined) to match Ark UI's Menu.Trigger, which also uses value to identify this trigger (see onTriggerValueChange). The prop still forwards to the real DOM node.
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
type"button" | "submit" | "reset" | undefined
disabledboolean | undefined
namestring | undefined
data-testidstring | undefined
PropTypeDefaultDescription
asChildboolean | undefined
insetboolean | undefinedfalse
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
variant{ default: string; brand: string; destructive: string; }default
data-testidstring | undefined

Explorer