Starting Point
v0.25.0
Start typing to search...
Go to Page
escClose

Dropdown

The dropdown displays a menu of actions anchored to its trigger, like the commands behind a "more" button or a user menu. For rich free-form content, reach for the popover; for picking a value in a form, use the select or combobox.

<button id="dd-demo-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown w-40" data-sp-toggle="#dd-demo-trigger">
  <div class="dropdown-label">My Account</div>
  <button class="dropdown-item">
    Profile
    <span class="dropdown-shortcut">⇧⌘P</span>
  </button>
  <button class="dropdown-item">
    Billing
    <span class="dropdown-shortcut">⌘B</span>
  </button>
  <button class="dropdown-item">
    Settings
    <span class="dropdown-shortcut">⌘S</span>
  </button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item">Support</button>
  <button class="dropdown-item" aria-disabled="true">API</button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item">
    Log out
    <span class="dropdown-shortcut">⇧⌘Q</span>
  </button>
</div>

Usage

Add the dropdown class to the menu panel and point it at its trigger with data-sp-toggle. It opens on click, positions itself against the trigger, supports arrow-key navigation, and closes when an action is chosen, on an outside click, or with Escape. Checkable items are the exception: toggling one keeps the menu open.

ClassDescription
dropdownAdd to the menu panel; carries the data-sp-* options
dropdown-labelAdd to a heading above a group of items
dropdown-itemAdd to each action, on a native <button> or <a>
dropdown-item-destructiveAdd to dropdown-item for a destructive action
dropdown-item-checkboxAdd to dropdown-item wrapping a hidden <input type="checkbox"> that holds the state
dropdown-item-radioAdd to dropdown-item wrapping a hidden <input type="radio">; share a name per set
dropdown-shortcutAdd to a <span> inside an item for a keyboard hint
dropdown-separatorAdd to an element between items to divide them
dropdown-subAdd to a nested dropdown that opens from an item
<!-- This is the trigger -->
<button id="my-trigger" class="btn btn-outline">Open</button>
 
<!-- This is the dropdown -->
<div class="dropdown" data-sp-toggle="#my-trigger">
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Settings</button>
</div>

Examples

Basic

A plain menu of actions.

<button id="dd-basic-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown" data-sp-toggle="#dd-basic-trigger">
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Billing</button>
  <button class="dropdown-item">Settings</button>
</div>

Groups

Group related items under a dropdown-label and divide groups with a dropdown-separator.

<button id="dd-groups-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown" data-sp-toggle="#dd-groups-trigger">
  <div class="dropdown-label">My Account</div>
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Billing</button>
  <button class="dropdown-item">Settings</button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item">GitHub</button>
  <button class="dropdown-item">Support</button>
</div>

Nest menus by pointing a second dropdown at an item; dropdown-sub sizes it, and hover mode opens it when the pointer reaches the item. With the keyboard, ArrowRight, Enter, or Space opens it and ArrowLeft or Escape closes it back to its item.

<button id="dd-sub-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown" data-sp-toggle="#dd-sub-trigger">
  <button class="dropdown-item">Team</button>
  <button id="dd-sub-invite" class="dropdown-item">
    Invite users
    <svg class="ml-auto" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
  </button>
  <button class="dropdown-item">
    New Team
    <span class="dropdown-shortcut">⌘+T</span>
  </button>
</div>
 
<div
  class="dropdown dropdown-sub"
  data-sp-toggle="#dd-sub-invite"
  data-sp-mode="hover"
  data-sp-placement="right-start"
>
  <button class="dropdown-item">Email</button>
  <button class="dropdown-item">Message</button>
  <button id="dd-sub-more" class="dropdown-item">
    More options
    <svg class="ml-auto" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
  </button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item">Advanced...</button>
</div>
 
<div
  class="dropdown dropdown-sub"
  data-sp-toggle="#dd-sub-more"
  data-sp-mode="hover"
  data-sp-placement="right-start"
>
  <button class="dropdown-item">Calendly</button>
  <button class="dropdown-item">Slack</button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item">Webhook</button>
</div>

Shortcuts

Hint an item's keyboard shortcut with dropdown-shortcut; it right-aligns inside the item.

<button id="dd-shortcuts-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown" data-sp-toggle="#dd-shortcuts-trigger">
  <div class="dropdown-label">My Account</div>
  <button class="dropdown-item">
    Profile
    <span class="dropdown-shortcut">⇧⌘P</span>
  </button>
  <button class="dropdown-item">
    Billing
    <span class="dropdown-shortcut">⌘B</span>
  </button>
  <button class="dropdown-item">
    Settings
    <span class="dropdown-shortcut">⌘S</span>
  </button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item">
    Log out
    <span class="dropdown-shortcut">⇧⌘Q</span>
  </button>
</div>

Icons

Lead items with an icon; svgs inside items are sized automatically.

<button id="dd-icons-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown" data-sp-toggle="#dd-icons-trigger">
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
    Profile
  </button>
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="14" x="2" y="5" rx="2"/><line x1="2" x2="22" y1="10" y2="10"/></svg>
    Billing
  </button>
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg>
    Settings
  </button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item dropdown-item-destructive">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m16 17 5-5-5-5"/><path d="M21 12H9"/><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/></svg>
    Log out
  </button>
</div>

Checkboxes

Make items checkable with dropdown-item-checkbox: a hidden checkbox input holds the state, so checked, change events, and form submission work like any input. Toggling doesn't close the menu, so several can be flipped in one visit.

<button id="dd-check-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown w-40" data-sp-toggle="#dd-check-trigger">
  <div class="dropdown-label">Appearance</div>
  <div class="dropdown-item dropdown-item-checkbox">
    <input type="checkbox" name="statusbar" checked />
    Status Bar
  </div>
  <div class="dropdown-item dropdown-item-checkbox" aria-disabled="true">
    <input type="checkbox" name="activitybar" />
    Activity Bar
  </div>
  <div class="dropdown-item dropdown-item-checkbox">
    <input type="checkbox" name="panel" />
    Panel
  </div>
</div>

Radio group

Give dropdown-item-radio inputs a shared name and the browser keeps the set exclusive; read the choice with input[name=position]:checked.

<button id="dd-radio-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown w-32" data-sp-toggle="#dd-radio-trigger">
  <div class="dropdown-label">Panel Position</div>
  <div class="dropdown-item dropdown-item-radio">
    <input type="radio" name="position" value="top" />
    Top
  </div>
  <div class="dropdown-item dropdown-item-radio">
    <input type="radio" name="position" value="bottom" checked />
    Bottom
  </div>
  <div class="dropdown-item dropdown-item-radio">
    <input type="radio" name="position" value="right" />
    Right
  </div>
</div>

Destructive

Mark a dangerous action with dropdown-item-destructive.

<button id="dd-destructive-trigger" class="btn btn-outline">Actions</button>
 
<div class="dropdown" data-sp-toggle="#dd-destructive-trigger">
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/></svg>
    Edit
  </button>
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v13"/><path d="m16 6-4-4-4 4"/><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/></svg>
    Share
  </button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item dropdown-item-destructive">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
    Delete
  </button>
</div>

Disabled

Add aria-disabled to disable an item.

<button id="dd-disabled-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown" data-sp-toggle="#dd-disabled-trigger">
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Billing</button>
  <button class="dropdown-item" aria-disabled="true">API</button>
</div>

Avatar

Any element can be the trigger, like an avatar button for a user menu.

<button id="dd-avatar-trigger" class="btn btn-ghost btn-icon rounded-full">
  <span class="avatar">
    <img
      class="avatar-image"
      src="https://images.unsplash.com/photo-1750390200282-bf7f669a9946?w=640&h=640&fit=facearea&facepad=3.2&auto=format&q=100"
      alt="Leila Navarro"
    />
    <span class="avatar-fallback">LN</span>
  </span>
</button>
 
<div class="dropdown" data-sp-toggle="#dd-avatar-trigger">
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z"/><path d="m9 12 2 2 4-4"/></svg>
    Account
  </button>
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="14" x="2" y="5" rx="2"/><line x1="2" x2="22" y1="10" y2="10"/></svg>
    Billing
  </button>
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.268 21a2 2 0 0 0 3.464 0"/><path d="M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326"/></svg>
    Notifications
  </button>
  <div class="dropdown-separator"></div>
  <button class="dropdown-item">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m16 17 5-5-5-5"/><path d="M21 12H9"/><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/></svg>
    Sign Out
  </button>
</div>

Complex

Groups, submenus, checkboxes, and radio items compose into a full application menu.

<button id="dd-complex-trigger" class="btn btn-outline">Open</button>
 
<div class="dropdown w-44" data-sp-toggle="#dd-complex-trigger">
  <div class="dropdown-label">File</div>
  <button class="dropdown-item">
    New File
    <span class="dropdown-shortcut">⌘N</span>
  </button>
  <button class="dropdown-item">
    Save
    <span class="dropdown-shortcut">⌘S</span>
  </button>
  <div class="dropdown-separator"></div>
  <div class="dropdown-label">View</div>
  <div class="dropdown-item dropdown-item-checkbox">
    <input type="checkbox" name="sidebar" checked />
    Show Sidebar
  </div>
  <div class="dropdown-item dropdown-item-checkbox">
    <input type="checkbox" name="statusbar" />
    Show Status Bar
  </div>
  <div class="dropdown-separator"></div>
  <button id="dd-complex-theme" class="dropdown-item">
    Theme
    <svg class="ml-auto" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
  </button>
</div>
 
<div
  class="dropdown dropdown-sub"
  data-sp-toggle="#dd-complex-theme"
  data-sp-mode="hover"
  data-sp-placement="right-start"
>
  <div class="dropdown-label">Appearance</div>
  <div class="dropdown-item dropdown-item-radio">
    <input type="radio" name="theme" value="light" checked />
    Light
  </div>
  <div class="dropdown-item dropdown-item-radio">
    <input type="radio" name="theme" value="dark" />
    Dark
  </div>
  <div class="dropdown-item dropdown-item-radio">
    <input type="radio" name="theme" value="system" />
    System
  </div>
</div>

Placement

Set where the menu opens relative to its trigger with data-sp-placement. It accepts any Floating UI placement, like top, right-start, or bottom-end, and the menu flips to the opposite side on its own when there isn't room.

<div class="flex gap-6">
  <button id="dd-placement-start" class="btn btn-outline btn-sm">Start</button>
  <button id="dd-placement-center" class="btn btn-outline btn-sm">
    Center
  </button>
  <button id="dd-placement-end" class="btn btn-outline btn-sm">End</button>
</div>
 
<div
  class="dropdown w-40"
  data-sp-toggle="#dd-placement-start"
  data-sp-placement="bottom-start"
>
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Settings</button>
</div>
<div
  class="dropdown w-40"
  data-sp-toggle="#dd-placement-center"
  data-sp-placement="bottom"
>
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Settings</button>
</div>
<div
  class="dropdown w-40"
  data-sp-toggle="#dd-placement-end"
  data-sp-placement="bottom-end"
>
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Settings</button>
</div>

Hover

Add data-sp-mode="hover" to open the menu on hover instead of click; it closes when the pointer leaves both the trigger and the menu.

<button id="dd-hover-trigger" class="btn btn-outline">Hover me</button>
 
<div class="dropdown" data-sp-toggle="#dd-hover-trigger" data-sp-mode="hover">
  <button class="dropdown-item">Profile</button>
  <button class="dropdown-item">Settings</button>
  <button class="dropdown-item">Logout</button>
</div>

Options

Set each option with its own data-sp-* attribute on the dropdown element.

AttributeValuesDefault
data-sp-toggleCSS selector
data-sp-placementFloating UI placementbottom-end
data-sp-offsetNumber4
data-sp-modeclick | hoverclick
data-sp-match-widthBooleanfalse
data-sp-itemCSS selector.dropdown-item
<div
  class="dropdown"
  data-sp-toggle="#my-trigger"
  data-sp-placement="bottom-start"
></div>

JavaScript

Events

Lifecycle events fire on the dropdown element; before* events are cancelable.

EventWhen
sp-beforeshowBefore opening (cancelable)
sp-showOpening
sp-shownOpen and settled
sp-beforehideBefore closing (cancelable)
sp-hideClosing
sp-hiddenClosed
el.addEventListener("sp-beforehide", (e) => {
  if (unsavedChanges) e.preventDefault(); // veto the close
});

Methods

Get the instance with sp.dropdown(el), then call its methods:

MethodDescription
show()Open the menu
hide()Close the menu
toggle()Open if closed, else close
const dropdown = sp.dropdown(document.querySelector("#my-dropdown"));
 
dropdown.show();