Dropdown Menu
<button class="btn btn-outline" popovertarget="demo-menu">Open</button>
<div class="dropdown-menu" id="demo-menu" popover style="width: 14rem"> <div class="dropdown-menu-group"> <div class="dropdown-menu-label">My Account</div> <button class="dropdown-menu-item" type="button"> Profile <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⇧</kbd><kbd class="kbd">⌘</kbd><kbd class="kbd">P</kbd></span> </button> <button class="dropdown-menu-item" type="button"> Billing <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⌘</kbd><kbd class="kbd">B</kbd></span> </button> <button class="dropdown-menu-item" type="button"> Settings <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⌘</kbd><kbd class="kbd">S</kbd></span> </button> </div>
<hr class="dropdown-menu-separator" />
<div class="dropdown-menu-group"> <div class="dropdown-menu-label">Team</div>
<button class="dropdown-menu-item dropdown-menu-sub-trigger" type="button" popovertarget="invite-menu"> Invite users </button>
<div class="dropdown-menu" id="invite-menu" popover style="width: 11rem"> <button class="dropdown-menu-item" type="button">Email</button> <button class="dropdown-menu-item" type="button">Message</button> <hr class="dropdown-menu-separator" /> <button class="dropdown-menu-item" type="button">More…</button> </div>
<button class="dropdown-menu-item" type="button"> New Team <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⌘</kbd><kbd class="kbd">T</kbd></span> </button> </div>
<hr class="dropdown-menu-separator" />
<div class="dropdown-menu-group"> <button class="dropdown-menu-item" type="button">GitHub</button> <button class="dropdown-menu-item" type="button">Support</button> <button class="dropdown-menu-item" type="button" data-disabled>API</button> </div>
<hr class="dropdown-menu-separator" />
<button class="dropdown-menu-item" type="button"> Log out <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⇧</kbd><kbd class="kbd">⌘</kbd><kbd class="kbd">Q</kbd></span> </button></div>| Class | Part |
|---|---|
.dropdown-menu | The popover panel |
.dropdown-menu-item | An action |
.dropdown-menu-label | Group heading — names the menu |
.dropdown-menu-separator | Divider |
.dropdown-menu-shortcut | Right-aligned key hint |
.dropdown-menu-group | Groups related items under one role |
.dropdown-menu-checkbox-item | Item that toggles |
.dropdown-menu-radio-group | Container for mutually exclusive items |
.dropdown-menu-radio-item | One choice within a radio group |
.dropdown-menu-item-indicator | Slot for the check or dot |
.dropdown-menu-sub-trigger | Item that opens a nested menu |
Attributes
Section titled “Attributes”| Attribute | On | Meaning |
|---|---|---|
data-pk-placement | the panel | bottom-start (default), bottom-end, top-start, top-end |
data-pk-offset | the panel | Gap from the trigger in pixels. Defaults to 4 |
data-pk-anchor | the panel | Selector to position against, when the trigger is not the popovertarget button |
data-pk-keep-open | an item | Activating it does not close the menu |
data-variant="destructive" | an item | Danger styling |
data-inset | an item or label | Aligns with items that have icons |
data-disabled | an item | Mirrored to aria-disabled, skipped by arrow keys |
data-state="open" | "closed" | panel and trigger | Set by the runtime |
The panel flips above the trigger when there is not enough room below, and is clamped to stay inside the viewport.
<button class="btn btn-outline" popovertarget="basic-menu">Open menu</button>
<div class="dropdown-menu" id="basic-menu" popover style="width: 13rem"> <button class="dropdown-menu-item" type="button">Profile</button> <button class="dropdown-menu-item" type="button">Settings</button> <hr class="dropdown-menu-separator" /> <button class="dropdown-menu-item" type="button">Sign out</button></div>Shortcuts
Section titled “Shortcuts”.dropdown-menu-shortcut pushes a key hint to the trailing edge. Put the keys inside it as
Kbd elements — one per key — and add kbd-group so they sit together. It is a
hint, not a binding: register the actual shortcut yourself.
<span class="dropdown-menu-shortcut kbd-group"> <kbd class="kbd">⌘</kbd><kbd class="kbd">S</kbd></span><button class="btn btn-outline" popovertarget="shortcuts-menu">Edit</button>
<div class="dropdown-menu" id="shortcuts-menu" popover style="width: 14rem"> <button class="dropdown-menu-item" type="button"> Undo <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⌘</kbd><kbd class="kbd">Z</kbd></span> </button> <button class="dropdown-menu-item" type="button"> Redo <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⇧</kbd><kbd class="kbd">⌘</kbd><kbd class="kbd">Z</kbd></span> </button> <hr class="dropdown-menu-separator" /> <button class="dropdown-menu-item" type="button"> Find <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⌘</kbd><kbd class="kbd">F</kbd></span> </button></div>Alignment
Section titled “Alignment”<button class="btn btn-outline" popovertarget="align-start">bottom-start</button>
<div class="dropdown-menu" id="align-start" popover style="width: 11rem"> <button class="dropdown-menu-item" type="button">Left edges align</button></div>
<button class="btn btn-outline" popovertarget="align-end">bottom-end</button>
<div class="dropdown-menu" id="align-end" popover data-pk-placement="bottom-end" style="width: 11rem"> <button class="dropdown-menu-item" type="button">Right edges align</button></div>With icons
Section titled “With icons”Give every item an icon, or use data-inset on the ones without so the labels still line up.
<button class="btn btn-outline" popovertarget="icon-menu">Actions</button>
<div class="dropdown-menu" id="icon-menu" popover style="width: 13rem"> <button class="dropdown-menu-item" type="button"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"></path> </svg> Edit </button> <button class="dropdown-menu-item" type="button" data-inset>Duplicate</button> <hr class="dropdown-menu-separator" /> <button class="dropdown-menu-item" type="button" data-variant="destructive"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6"></path> </svg> Delete </button></div>Checkbox items
Section titled “Checkbox items”Each item keeps its own state in aria-checked, and pk:menu:change fires with
{ checked, value } where value comes from data-value. Pair them with data-pk-keep-open so
several can be toggled in one visit.
<button class="btn btn-outline" popovertarget="view-menu">View</button>
<div class="dropdown-menu" id="view-menu" popover style="width: 14rem"> <div class="dropdown-menu-label">Appearance</div> <hr class="dropdown-menu-separator" />
<div class="dropdown-menu-group"> <button class="dropdown-menu-checkbox-item" type="button" data-value="status" aria-checked="true" data-pk-keep-open> <span class="dropdown-menu-item-indicator"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M20 6 9 17l-5-5"></path> </svg> </span> Status bar </button>
<button class="dropdown-menu-checkbox-item" type="button" data-value="panel" data-pk-keep-open> <span class="dropdown-menu-item-indicator"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M20 6 9 17l-5-5"></path> </svg> </span> Activity bar </button> </div></div>Radio items
Section titled “Radio items”Selecting one clears its siblings in the same .dropdown-menu-radio-group, and leaves checkbox
items elsewhere in the menu alone.
<button class="btn btn-outline" popovertarget="density-menu">Density</button>
<div class="dropdown-menu" id="density-menu" popover style="width: 14rem"> <div class="dropdown-menu-label">Row height</div> <hr class="dropdown-menu-separator" />
<div class="dropdown-menu-radio-group"> <button class="dropdown-menu-radio-item" type="button" data-value="compact" aria-checked="true"> <span class="dropdown-menu-item-indicator"><span></span></span> Compact </button>
<button class="dropdown-menu-radio-item" type="button" data-value="comfortable"> <span class="dropdown-menu-item-indicator"><span></span></span> Comfortable </button> </div></div>Submenus
Section titled “Submenus”A .dropdown-menu-sub-trigger points popovertarget at a nested .dropdown-menu. Put the
submenu inside its parent in the DOM — that containment is what makes the browser treat them as
parent and child, so opening the submenu does not dismiss the menu it came from.
<button class="btn btn-outline" popovertarget="file-menu">File</button>
<div class="dropdown-menu" id="file-menu" popover style="width: 13rem"> <button class="dropdown-menu-item" type="button">New window</button>
<button class="dropdown-menu-item dropdown-menu-sub-trigger" type="button" popovertarget="share-menu"> Share </button>
<!-- Nested inside its parent: that is what makes the browser treat the two popovers as parent and child. --> <div class="dropdown-menu" id="share-menu" popover style="width: 12rem"> <button class="dropdown-menu-item" type="button">Email link</button> <button class="dropdown-menu-item" type="button">Copy link</button> </div>
<hr class="dropdown-menu-separator" /> <button class="dropdown-menu-item" type="button" data-variant="destructive">Close window</button></div>→ opens a submenu and focuses its first item; ← closes it and returns to the trigger. Moving
the pointer to a different item closes it too.
Checkboxes Icons
Section titled “Checkboxes Icons”An item can carry both: the indicator on the trailing edge and its own icon inline.
<button class="btn btn-outline" popovertarget="filters-menu">Filters</button>
<div class="dropdown-menu" id="filters-menu" popover style="width: 14rem"> <div class="dropdown-menu-label">Show</div> <hr class="dropdown-menu-separator" />
<button class="dropdown-menu-checkbox-item" type="button" data-value="open" aria-checked="true" data-pk-keep-open> <span class="dropdown-menu-item-indicator"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M20 6 9 17l-5-5"></path> </svg> </span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <circle cx="12" cy="12" r="10"></circle> </svg> Open issues </button>
<button class="dropdown-menu-checkbox-item" type="button" data-value="closed" data-pk-keep-open> <span class="dropdown-menu-item-indicator"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M20 6 9 17l-5-5"></path> </svg> </span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M20 6 9 17l-5-5"></path> </svg> Closed issues </button></div>Radio Icons
Section titled “Radio Icons”<button class="btn btn-outline" popovertarget="theme-menu">Theme</button>
<div class="dropdown-menu" id="theme-menu" popover style="width: 13rem"> <div class="dropdown-menu-radio-group"> <button class="dropdown-menu-radio-item" type="button" data-value="light" aria-checked="true"> <span class="dropdown-menu-item-indicator"><span></span></span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <circle cx="12" cy="12" r="4"></circle> <path d="M12 2v2m0 16v2M2 12h2m16 0h2"></path> </svg> Light </button> <button class="dropdown-menu-radio-item" type="button" data-value="dark"> <span class="dropdown-menu-item-indicator"><span></span></span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8Z"></path> </svg> Dark </button> </div></div>Destructive
Section titled “Destructive”data-variant="destructive" recolours the item and its icon, and gives it a destructive surface
when focused.
<button class="btn btn-outline" popovertarget="danger-menu">Manage</button>
<div class="dropdown-menu" id="danger-menu" popover style="width: 13rem"> <button class="dropdown-menu-item" type="button">Rename</button> <button class="dropdown-menu-item" type="button">Duplicate</button> <hr class="dropdown-menu-separator" /> <button class="dropdown-menu-item" type="button" data-variant="destructive"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6"></path> </svg> Delete project </button></div>Complex
Section titled “Complex”Labels, groups, shortcuts, a submenu, a disabled item and a destructive action in one menu.
<button class="btn btn-outline" popovertarget="complex-menu">Account</button>
<div class="dropdown-menu" id="complex-menu" popover style="width: 15rem"> <div class="dropdown-menu-label">patrick@example.com</div> <hr class="dropdown-menu-separator" />
<div class="dropdown-menu-group"> <button class="dropdown-menu-item" type="button"> Profile <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⇧</kbd><kbd class="kbd">⌘</kbd><kbd class="kbd">P</kbd></span> </button> <button class="dropdown-menu-item" type="button"> Settings <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⌘</kbd><kbd class="kbd">,</kbd></span> </button> </div>
<hr class="dropdown-menu-separator" />
<button class="dropdown-menu-item dropdown-menu-sub-trigger" type="button" popovertarget="complex-sub"> Invite people </button>
<div class="dropdown-menu" id="complex-sub" popover style="width: 12rem"> <button class="dropdown-menu-item" type="button">Email</button> <button class="dropdown-menu-item" type="button">Copy invite link</button> </div>
<hr class="dropdown-menu-separator" />
<button class="dropdown-menu-item" type="button" data-disabled>API access</button> <button class="dropdown-menu-item" type="button" data-variant="destructive"> Sign out <span class="dropdown-menu-shortcut kbd-group"><kbd class="kbd">⇧</kbd><kbd class="kbd">⌘</kbd><kbd class="kbd">Q</kbd></span> </button></div>Set dir="rtl" on the page or on any subtree — padding, corners and positions follow the reading
direction on their own. See the button page for a live example.
Hover and focus
Section titled “Hover and focus”An item paints on :focus, not :hover — and the pointer moves focus rather than lighting a
separate state. That is what Radix does inside shadcn/ui, and it means keyboard and pointer share
one highlight instead of two that can disagree.
The highlight is --accent, which is deliberately quiet: 3% grey on white, and one step up from
the panel in dark. It has to differ from --popover or a menu has no visible hover at all — the
palette test checks exactly that pair.
Keyboard
Section titled “Keyboard”| Key | Action |
|---|---|
| ↓ / ↑ | Move between enabled items, wrapping at the ends |
| Home / End | First / last enabled item |
| a–z, 0–9 | Type-ahead to the first item starting with what you type |
| → | Open the submenu under the cursor |
| ← | Close a submenu and return to its trigger |
| Esc / Tab | Close and return focus to the trigger |
Items are real <button> elements, so Enter and Space activate them without extra code.
Disabled items keep aria-disabled="true" rather than disabled, staying announced but skipped.