Dropdown

A Tailwind CSS dropdown component for displaying a list of actions or options.

<div class="dropdown">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    Options
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">New file</a>
    <a href="#" class="dropdown-item">Copy link</a>
    <div class="dropdown-separator"></div>
    <a href="#" class="dropdown-item">Edit</a>
    <a href="#" class="dropdown-item">Rename</a>
    <div class="dropdown-separator"></div>
    <a href="#" class="dropdown-item">Delete</a>
  </div>
</div>

With icons

Add icons to dropdown items for better visual hierarchy.

<div class="dropdown">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    Options
  </button>
  <div class="dropdown-menu">
    <a href="#" 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="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"></path><path d="M14 2v5a1 1 0 0 0 1 1h5"></path><path d="M9 15h6"></path><path d="M12 18v-6"></path></svg>
      New file
    </a>
    <a href="#" 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 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
      Copy link
    </a>
    <div class="dropdown-separator"></div>
    <a href="#" 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><path d="m15 5 4 4"></path></svg>
      Edit
    </a>
    <a href="#" 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 20h-1a2 2 0 0 1-2-2 2 2 0 0 1-2 2H6"></path><path d="M13 8h7a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-7"></path><path d="M5 16H4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h1"></path><path d="M6 4h1a2 2 0 0 1 2 2 2 2 0 0 1 2-2h1"></path><path d="M9 6v12"></path></svg>
      Rename
    </a>
    <div class="dropdown-separator"></div>
    <a href="#" 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 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M3 6h18"></path><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
      Delete
    </a>
  </div>
</div>

With labels

Use .dropdown-label to group items with a heading.

<div class="dropdown">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    My Account
  </button>
  <div class="dropdown-menu">
    <div class="dropdown-label">Settings</div>
    <a href="#" 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"></path><circle cx="12" cy="7" r="4"></circle></svg>
      Profile
    </a>
    <a href="#" 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"></rect><line x1="2" x2="22" y1="10" y2="10"></line></svg>
      Billing
    </a>
    <a href="#" 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><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"></path></svg>
      Notifications
    </a>
    <div class="dropdown-separator"></div>
    <div class="dropdown-label">Help</div>
    <a href="#" 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 7v14"></path><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"></path></svg>
      Documentation
    </a>
    <a href="#" 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 14h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7a9 9 0 0 1 18 0v7a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3"></path></svg>
      Support
    </a>
  </div>
</div>

Disabled items

Use aria-disabled="true" to disable an item. Add tabindex="-1" to prevent tab navigation to the item.

<div class="dropdown">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    Actions
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Edit</a>
    <a href="#" class="dropdown-item" aria-disabled="true" tabindex="-1"
      >Duplicate</a
    >
    <a href="#" class="dropdown-item">Archive</a>
    <div class="dropdown-separator"></div>
    <a href="#" class="dropdown-item" aria-disabled="true" tabindex="-1"
      >Delete</a
    >
  </div>
</div>

Placement

Use data-sp-placement to control the dropdown position (default is bottom-end).

<div class="dropdown" data-sp-placement="bottom-start">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    bottom-start
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="bottom">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    bottom
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="bottom-end">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    bottom-end
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="top-start">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    top-start
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="top">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    top
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="top-end">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    top-end
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="left-start">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    left-start
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="left">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    left
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="left-end">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    left-end
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="right-start">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    right-start
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="right">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    right
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-placement="right-end">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    right-end
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>

Offset

Use data-sp-offset to control the distance between the trigger and the menu (default is 4).

<div class="dropdown" data-sp-offset="0">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    No Offset
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    Default (4)
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>
 
<div class="dropdown" data-sp-offset="12">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    Offset 12
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
  </div>
</div>

How it works

The dropdown component uses a small JavaScript module that handles opening, closing, positioning, and keyboard navigation.

Structure

A dropdown consists of three parts:

  1. .dropdown - Container that wraps the trigger and menu
  2. [data-sp-toggle="dropdown"] - Button that opens/closes the menu
  3. .dropdown-menu - The menu panel with items
<div class="dropdown">
  <button type="button" data-sp-toggle="dropdown" aria-expanded="false">
    Open Menu
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Item 1</a>
    <a href="#" class="dropdown-item">Item 2</a>
  </div>
</div>

Opening and closing

Use data attributes to control the dropdown without writing JavaScript.

Add data-sp-toggle="dropdown" to the trigger button. The JavaScript will find the .dropdown-menu sibling and toggle it:

<button data-sp-toggle="dropdown" aria-expanded="false">Open</button>

Clicking outside the dropdown or pressing Escape closes the menu. Clicking an item also closes the dropdown by default.

For programmatic control, use the global StartingPointUI.dropdown module:

const dropdown = document.querySelector(".dropdown");
 
StartingPointUI.dropdown.open(dropdown);
StartingPointUI.dropdown.close(dropdown);
StartingPointUI.dropdown.toggle(dropdown);

Animation

The dropdown includes a default fade and zoom animation. When opened, the JavaScript sets data-state="open" on the menu element.

To customize animations, add no-animation to disable the defaults and use your own classes with data-[state=open]: selectors:

<div class="dropdown-menu no-animation data-[state=open]:animate-in data-[state=open]:slide-in-from-top-2">
  <!-- Custom slide animation -->
</div>
<div class="dropdown">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    Default
  </button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
    <a href="#" class="dropdown-item">Logout</a>
  </div>
</div>
 
<div class="dropdown">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    No Animation
  </button>
  <div class="dropdown-menu no-animation">
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
    <a href="#" class="dropdown-item">Logout</a>
  </div>
</div>
 
<div class="dropdown">
  <button
    class="btn btn-outline"
    type="button"
    data-sp-toggle="dropdown"
    aria-expanded="false"
  >
    Slide from Top
  </button>
  <div
    class="dropdown-menu no-animation data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:slide-in-from-top-2"
  >
    <a href="#" class="dropdown-item">Profile</a>
    <a href="#" class="dropdown-item">Settings</a>
    <a href="#" class="dropdown-item">Logout</a>
  </div>
</div>

The default animations use tw-animate-css utilities. You can customize or replace these with your own animations.

Accessibility

The dropdown JavaScript module provides full keyboard navigation and proper ARIA attributes.

For proper accessibility, add aria-expanded="false" to the trigger button:

<button data-sp-toggle="dropdown" aria-expanded="false">Open</button>

The JavaScript will automatically update aria-expanded when the dropdown opens and closes.

Keyboard navigation

KeyAction
Enter / SpaceOpens/closes dropdown when trigger is focused
EscapeCloses the dropdown
ArrowDownMove focus to next item
ArrowUpMove focus to previous item
HomeMove focus to first item
EndMove focus to last item

Class reference

All available classes for the dropdown component.

ClassDescription
dropdownContainer for the dropdown
dropdown-menuThe menu panel that appears on toggle
dropdown-itemIndividual menu item
dropdown-labelLabel/heading for grouping items
dropdown-separatorHorizontal divider between items
no-animationDisables default animation on dropdown-menu
<div class="dropdown">
  <button data-sp-toggle="dropdown">Open</button>
  <div class="dropdown-menu">
    <div class="dropdown-label">Group</div>
    <a href="#" class="dropdown-item">Item</a>
    <div class="dropdown-separator"></div>
    <a href="#" class="dropdown-item">Item</a>
  </div>
</div>

Data attributes

All data attributes for the dropdown component.

AttributeElementDescription
data-sp-toggle="dropdown"ButtonToggles the dropdown
data-sp-placement.dropdownMenu position (default: bottom-end)
data-sp-offset.dropdownDistance from trigger in pixels (default: 4)
data-stateMenuSet to open when menu is visible
aria-disabled="true"ItemDisables the item visually and functionally
<div class="dropdown" data-sp-placement="bottom-start" data-sp-offset="8">
  <button data-sp-toggle="dropdown" aria-expanded="false">Open</button>
  <div class="dropdown-menu">
    <a href="#" class="dropdown-item">Enabled</a>
    <a href="#" class="dropdown-item" aria-disabled="true">Disabled</a>
  </div>
</div>