Dropdown Menu
A headless, accessible dropdown menu with submenus, checkbox and radio items, typeahead, and full keyboard navigation.
Features
- Menu button pattern
- Checkbox and radio items
- Submenu support
- Active descendant tracking
- Typeahead
- Headless styling
Installation
npm install @ariaui/dropdown-menu
Examples
Four playgrounds migrated from the legacy doc: a full account-style menu, a submenu-only flow, selectionMode="multiple" with CheckboxItem, and a RadioGroup block. Each has its own snippet; styling uses semantic tokens (border-border, bg-background, etc.).
Keyboard support includes roving focus, typeahead, arrows in submenus, and Escape to dismiss—see the keyboard table below.
Full menu
Account header, shortcuts, submenu, checkbox and radio groups, and a destructive-style action.
No preview output yet.
With submenu
Nested menu using Sub, SubTrigger, and SubContent.
No preview output yet.
With checkboxes
Multiple selection with CheckboxItem rows for independent toggles.
No preview output yet.
With radio group
RadioGroup coordinates mutually exclusive RadioItem values.
No preview output yet.
Framer Motion
Animated root and submenu content using asChild composition with Framer Motion.
No preview output yet.
Anatomy
import * as DropdownMenu from "@ariaui/dropdown-menu";
export default function Example() {
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger />
<DropdownMenu.Content>
<DropdownMenu.Group>
<DropdownMenu.Label />
<DropdownMenu.Item />
</DropdownMenu.Group>
<DropdownMenu.Separator />
<DropdownMenu.Sub>
<DropdownMenu.SubTrigger />
<DropdownMenu.SubContent>
<DropdownMenu.Item />
</DropdownMenu.SubContent>
</DropdownMenu.Sub>
<DropdownMenu.CheckboxItem />
<DropdownMenu.RadioGroup>
<DropdownMenu.RadioItem />
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
);
}
API Reference
Root
State container. Owns the open state, selection mode, and provides context to all child components.
| Prop | Type | Default |
|---|---|---|
onValueChange | (value: string) => void | — |
open | boolean | — |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | — |
selectionMode | "single" | "multiple" | "single" |
offset | { x: number; y: number } | — |
Trigger
Button that toggles the dropdown menu. Focus returns here when the menu closes.
| Attribute | Values |
|---|---|
| aria-haspopup | menu |
| aria-expanded | "true" when open, "false" when closed |
| aria-controls | ID of the Content element |
Content
Floating menu container. Manages item registration, active-item tracking via aria-activedescendant, and keyboard navigation.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
| Attribute | Values |
|---|---|
| role | menu |
| aria-labelledby | ID of the Trigger element |
| aria-activedescendant | ID of the currently active item |
Item
A selectable menu item. Activates on click, Enter, or Space.
| Prop | Type | Default |
|---|---|---|
value | string | — |
disabled | boolean | false |
| Attribute | Values |
|---|---|
| role | menuitem |
| [data-active] | Present when keyboard-highlighted |
| [data-disabled] | Present when disabled |
CheckboxItem
A menu item with checkbox semantics. Toggles checked state on activation.
| Prop | Type | Default |
|---|---|---|
checked | boolean | — |
defaultChecked | boolean | false |
onCheckedChange | (checked: boolean) => void | — |
disabled | boolean | false |
| Attribute | Values |
|---|---|
| role | menuitemcheckbox |
| aria-checked | "true" or "false" |
| [data-active] | Present when keyboard-highlighted |
| [data-disabled] | Present when disabled |
RadioGroup
Groups related RadioItem components and manages the selected value.
| Prop | Type | Default |
|---|---|---|
value | string | — |
defaultValue | string | — |
onValueChange | (value: string) => void | — |
RadioItem
A menu item with radio semantics. Selects its value within the parent RadioGroup on activation.
| Prop | Type | Default |
|---|---|---|
value* | string | — |
disabled | boolean | false |
| Attribute | Values |
|---|---|
| role | menuitemradio |
| aria-checked | "true" when selected |
| [data-active] | Present when keyboard-highlighted |
| [data-disabled] | Present when disabled |
Sub
State container for a submenu. Wraps SubTrigger and SubContent.
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | — |
offset | { x: number; y: number } | — |
SubTrigger
A menu item that opens a nested submenu on hover or keyboard.
| Attribute | Values |
|---|---|
| role | menuitem |
| aria-haspopup | menu |
| aria-expanded | "true" when submenu is open |
| aria-controls | ID of the SubContent element |
| [data-active] | Present when keyboard-highlighted |
SubContent
Floating container for submenu items. Positioned relative to SubTrigger.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
| Attribute | Values |
|---|---|
| role | menu |
| aria-activedescendant | ID of the currently active submenu item |
Group
Groups related menu items.
Label
Non-interactive label for a group of items.
Separator
Visual divider between menu sections.
| Attribute | Values |
|---|---|
| role | separator |
Keyboard
| Shortcut | Action |
|---|---|
| ↓ | Open the menu (from trigger) or move to the next item. Wraps to first. |
| ↑ | Open the menu targeting last item (from trigger) or move to the previous item. Wraps to last. |
| Home | Move to the first enabled item. |
| End | Move to the last enabled item. |
| Enter/Space | Open the menu (from trigger) or activate the focused item. |
| Esc | Close the current menu layer and return focus to its trigger. |
| → | Open a submenu when a SubTrigger is focused (LTR). |
| ← | Close a submenu and return to the parent menu (LTR). |
Accessibility
The Dropdown Menu component implements the WAI-ARIA Menu Button pattern using the aria-activedescendant model:
Triggerexposesaria-haspopup="menu",aria-expanded, andaria-controlspointing to the Content.Contentrenders asrole="menu"witharia-labelledbyreferencing the Trigger andaria-activedescendanttracking the active item.Itemrenders asrole="menuitem"withdata-activefor the focused state.CheckboxItemrenders asrole="menuitemcheckbox"witharia-checked.RadioItemrenders asrole="menuitemradio"witharia-checked.SubTriggercarriesaria-haspopup="menu"andaria-expandedto announce submenu availability.- DOM focus stays on the menu container during keyboard navigation; active items are communicated via
aria-activedescendant. - Navigation is cyclic, disabled items are skipped, and typeahead prefix matching is supported.