Dropdown

A menu of actions or options, triggered by a button

Installation

pnpm add @wandercom/design-system-web

Usage

Built on Radix UI primitives, the dropdown supports icons, keyboard shortcuts, separators, checkboxes, radio groups, and nested submenus.

import {
  Dropdown,
  DropdownTrigger,
  DropdownContent,
  DropdownItem,
} from '@wandercom/design-system-web/ui/dropdown';

export function Example() {
  return (
    <Dropdown>
      <DropdownTrigger asChild>
        <button>Open menu</button>
      </DropdownTrigger>
      <DropdownContent>
        <DropdownItem>Profile</DropdownItem>
        <DropdownItem>Settings</DropdownItem>
        <DropdownItem>Logout</DropdownItem>
      </DropdownContent>
    </Dropdown>
  );
}

Examples

Trigger variants

The dropdown trigger supports a styled default variant matching SelectTrigger, a sm size, and an unstyled variant for custom trigger elements via asChild.

Loading example...

Basic menu

A simple dropdown menu with basic items.

Loading example...

With icons

Add icons to menu items for visual clarity.

Loading example...

With separators and labels

Group related items with separators and labels.

Loading example...

With keyboard shortcuts

Display keyboard shortcuts alongside menu items.

Loading example...

With checkbox items

Use checkboxes for togglable options.

Loading example...

With radio group

Use radio groups for mutually exclusive options.

Loading example...

With submenu

Create nested menus for hierarchical options.

Loading example...

Destructive variant

Use the destructive variant to indicate dangerous actions.

Loading example...

Inset items

Use the inset prop to align items with labels or icons.

Loading example...

Props

open?:

boolean
Controlled open state of the dropdown menu.

defaultOpen?:

boolean
Default open state for uncontrolled usage.

onOpenChange?:

(open: boolean) => void
Event handler called when the open state changes.

variant?:

'default' | 'unstyled'
Visual variant. Default renders a styled trigger matching SelectTrigger. Unstyled removes all styles for use with asChild.

size?:

'default' | 'sm'
Size of the trigger. Defaults to "default" (h-12). Use "sm" for a compact height (h-10).

asChild?:

boolean
Renders the child element directly, merging props instead of wrapping in a button. Skips variant styles when true.

className?:

string
Additional CSS classes to apply.

className?:

string
Additional CSS classes to apply to the content container.

sideOffset?:

number
Distance in pixels from the trigger. Defaults to 4.

side?:

'top' | 'right' | 'bottom' | 'left'
Preferred side of the trigger to render against. Defaults to "bottom".

align?:

'start' | 'center' | 'end'
Alignment relative to the trigger.

alignOffset?:

number
Offset in pixels from the alignment axis.

className?:

string
Additional CSS classes to apply.

variant?:

'default' | 'destructive'
Visual variant. Defaults to "default".

inset?:

boolean
Adds left padding to align with labels or icons.

disabled?:

boolean
Disables the menu item.

onSelect?:

(event: Event) => void
Event handler called when the item is selected.

className?:

string
Additional CSS classes to apply.

checked?:

boolean | "indeterminate"
Checked state of the checkbox.

onCheckedChange?:

(checked: boolean) => void
Event handler called when the checked state changes.

disabled?:

boolean
Disables the checkbox item.

className?:

string
Additional CSS classes to apply.

value?:

string
The controlled selected value.

onValueChange?:

(value: string) => void
Event handler called when the selected value changes.

value:

string
The unique value of this radio item.

disabled?:

boolean
Disables the radio item.

className?:

string
Additional CSS classes to apply.

inset?:

boolean
Adds left padding to align with inset items.

className?:

string
Additional CSS classes to apply.

className?:

string
Additional CSS classes to apply.

className?:

string
Additional CSS classes to apply.

open?:

boolean
Controlled open state of the submenu.

defaultOpen?:

boolean
Default open state for uncontrolled usage.

onOpenChange?:

(open: boolean) => void
Event handler called when the open state changes.

inset?:

boolean
Adds left padding to align with inset items.

disabled?:

boolean
Disables the submenu trigger.

className?:

string
Additional CSS classes to apply.

sideOffset?:

number
Distance in pixels from the sub-trigger. Defaults to 13.

className?:

string
Additional CSS classes to apply.

Accessibility

The dropdown is built on Radix UI primitives with full accessibility support:

  • Uses semantic menu role and appropriate ARIA attributes
  • Supports keyboard navigation with arrow keys
  • Opens and closes with Enter or Space
  • Closes on Escape key press
  • Supports typeahead to jump to matching items
  • Manages focus automatically when opened and closed
  • Honors disabled state on individual items
  • Checkbox and radio items include proper ARIA state attributes
Dropdown