Skip to main content

dropdown menu

Displays a menu to the user -- such as a set of actions or functions -- triggered by a button.

Philosophy

Dropdown menus are the Swiss Army knife of action UIs. They group related actions behind a single trigger, keeping interfaces clean while maintaining discoverability. Our implementation builds on @gentleduck/primitives/dropdown-menu which wraps the base Menu primitive, adding checkbox items, radio groups, sub-menus, and keyboard navigation. The wrapper adds design-system styling while the primitive handles all interaction logic.

How It's Built

Loading diagram...

Installation


npx @gentleduck/cli add dropdown-menu

npx @gentleduck/cli add dropdown-menu

Usage

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
<DropdownMenu>
  <DropdownMenuTrigger>Open</DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuLabel>My Account</DropdownMenuLabel>
    <DropdownMenuSeparator />
    <DropdownMenuItem>Profile</DropdownMenuItem>
    <DropdownMenuItem>Billing</DropdownMenuItem>
    <DropdownMenuItem>Team</DropdownMenuItem>
    <DropdownMenuItem>Subscription</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
  <DropdownMenuTrigger>Open</DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuLabel>My Account</DropdownMenuLabel>
    <DropdownMenuSeparator />
    <DropdownMenuItem>Profile</DropdownMenuItem>
    <DropdownMenuItem>Billing</DropdownMenuItem>
    <DropdownMenuItem>Team</DropdownMenuItem>
    <DropdownMenuItem>Subscription</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Component Composition

Loading diagram...

Examples

Checkboxes

Radio Group

API Reference

The root component that manages open/closed state and provides context to all children.

PropTypeDefaultDescription
openboolean--Controlled open state
defaultOpenbooleanfalseInitial open state (uncontrolled)
onOpenChange(open: boolean) => void--Callback when open state changes
dir'ltr' | 'rtl'--Text direction. Resolved by primitives useDirection (dir prop -> DirectionProvider -> 'ltr').
modalbooleantrueWhen true, interaction with outside elements is disabled and only menu content is visible to screen readers

Button that toggles the dropdown menu. Renders a <button> with aria-haspopup="menu".

PropTypeDefaultDescription
asChildboolean--Render as the child element instead of a <button>
disabledbooleanfalseDisables the trigger

Sets aria-expanded, aria-controls, and data-state automatically.

The dropdown content area. Handles positioning, focus management, keyboard navigation, and dismiss behavior. Automatically wrapped in a Portal.

PropTypeDefaultDescription
side'top' | 'right' | 'bottom' | 'left''bottom'Preferred side relative to the trigger
sideOffsetnumber4Main-axis offset from trigger
align'start' | 'center' | 'end''start'Cross-axis alignment
alignOffsetnumber--Cross-axis offset
avoidCollisionsbooleantrueFlip to avoid viewport overflow
collisionPaddingnumber--Padding from viewport edges
classNamestring--Additional CSS class names

Exposes data-state="open" / data-state="closed" and data-side for CSS animation.

When using popper positioning, the following CSS custom properties are available:

  • --gentleduck-dropdown-menu-content-transform-origin
  • --gentleduck-dropdown-menu-content-available-width
  • --gentleduck-dropdown-menu-content-available-height
  • --gentleduck-dropdown-menu-trigger-width
  • --gentleduck-dropdown-menu-trigger-height

Groups related items together. Renders a <div> with role="group".

PropTypeDefaultDescription
classNamestring--Additional CSS class names

A non-interactive label for grouping menu items.

PropTypeDefaultDescription
insetboolean--Adds start padding to align with items that have icons
classNamestring--Additional CSS class names

An individual menu action item. Renders a <div> with role="menuitem".

PropTypeDefaultDescription
variant'default' | 'destructive''default'Style variant for the item
insetboolean--Adds start padding to align with items that have icons
disabledboolean--Prevents interaction and styles the item as disabled
onSelect(event: Event) => void--Called when the item is selected via click or keyboard
textValuestring--Text override for typeahead search
classNamestring--Additional CSS class names

Exposes data-highlighted when focused and data-disabled when disabled.

A menu item with a toggleable checkbox indicator.

PropTypeDefaultDescription
checkedboolean | 'indeterminate'--Controlled checked state
onCheckedChange(checked: boolean) => void--Callback when checked state changes
disabledboolean--Prevents interaction
classNamestring--Additional CSS class names

Groups radio items together for single-selection behavior.

PropTypeDefaultDescription
valuestring--The currently selected radio value
onValueChange(value: string) => void--Callback when the selected value changes

A radio-selectable menu item. Must be used inside DropdownMenuRadioGroup.

PropTypeDefaultDescription
valuestring(required)The value representing this radio item
disabledboolean--Prevents interaction
classNamestring--Additional CSS class names

A visual divider between groups of menu items. Renders a styled <div>.

PropTypeDefaultDescription
classNamestring--Additional CSS class names

Displays a keyboard shortcut hint next to a menu item.

PropTypeDefaultDescription
classNamestring--Additional CSS class names

Wrapper for a submenu. Manages nested open state.

PropTypeDefaultDescription
openboolean--Controlled open state
defaultOpenbooleanfalseInitial open state (uncontrolled)
onOpenChange(open: boolean) => void--Callback when open state changes

Trigger element for a submenu. Displays a chevron icon indicating a nested menu.

PropTypeDefaultDescription
insetboolean--Adds start padding to align with inset menu items
disabledboolean--Disables the trigger
classNamestring--Additional CSS class names

Content container for a submenu. Positioned to the side of the sub-trigger.

PropTypeDefaultDescription
sideOffsetnumber--Main-axis offset from trigger
alignOffsetnumber--Cross-axis offset
classNamestring--Additional CSS class names

Exposes the same --gentleduck-dropdown-menu-* CSS custom properties as DropdownMenuContent.

RTL Support

Set dir="rtl" on DropdownMenu for a local override, or set DirectionProvider once at app/root level for global direction.