Dropdowns show a contextual menu when a trigger is clicked. They are the universal menu pattern, used in the site header, sticky bars, tool toolbars, and page content. One component, same classes everywhere.
Trigger patterns
The trigger is the element that opens the dropdown. provides built-in styling, no additional classes needed.
Icon + text + chevron
The most common trigger. The rotates 180 degrees when the dropdown is open.
<div class="dropdown">
<button class="dropdown-trigger" type="button" aria-haspopup="true" aria-expanded="false">
<div class="svg-icn" data-icon="user"><!-- svg --></div>
<span>Account</span>
<div class="svg-icn dropdown-chevron" data-icon="chevron-down"><!-- svg --></div>
</button>
<div class="dropdown-menu">
<!-- items -->
</div>
</div>
Icon-only trigger
For toolbars and compact contexts. No text, no chevron. The icon alone signals "click for options."
<button class="dropdown-trigger" type="button" aria-haspopup="true" aria-expanded="false" aria-label="More options">
<div class="svg-icn" data-icon="more-horizontal"><!-- svg --></div>
</button>
Button trigger
For page content where the trigger should look like a standard button.
<button class="dropdown-trigger button" data-variant="outline" type="button" ...>
Options
<div class="svg-icn dropdown-chevron"><!-- chevron svg --></div>
</button>
When to use a chevron
| Scenario | Chevron? | Why |
|---|---|---|
| Selector-style trigger (choosing a value) | Yes | Signals "pick from a list" |
| Navigation dropdown (Account, Profile) | Yes | Shows the menu expands downward |
| Icon-only trigger (⋯ more, settings gear) | No | The icon itself implies a menu |
| Button trigger with label | Optional | Use when the button looks like a selector |
Menu alignment
Menus open left-aligned by default. Add to right-align from the trigger.
<div class="dropdown-menu is-right">
Use when the dropdown is near the right edge of the viewport to prevent overflow.
Item patterns
Text-only item
The simplest item, just a label with no icon.
<button class="dropdown-item" role="menuitem" type="button">Admin</button>
Icon-left item
An icon before the text reinforces the action. Use for action verbs like Edit, Download, Delete.
<button class="dropdown-item" role="menuitem" type="button">
<div class="svg-icn" data-icon="settings"><!-- svg --></div>
<span>Settings</span>
</button>
Icon-right item (trailing content)
Use to push trailing content to the right edge. Ideal for keyboard shortcuts, badges, status indicators, or chevrons hinting at sub-menus.
<button class="dropdown-item" role="menuitem" type="button">
<span>Undo</span>
<span class="dropdown-item-end"><kbd>Ctrl+Z</kbd></span>
</button>
Item with description
Use for supporting text below the label.
<button class="dropdown-item" role="menuitem" type="button">
<div>
<div>From template</div>
<div class="dropdown-desc">Choose from pre-built project templates</div>
</div>
</button>
Avatar item
For user menus showing the logged-in user's identity.
Section labels
Use to create non-interactive section headers that group items.
<div class="dropdown-label">Actions</div>
<button class="dropdown-item" role="menuitem" type="button">Rename</button>
...
<div class="dropdown-divider" role="separator"></div>
<div class="dropdown-label">Danger zone</div>
<button class="dropdown-item dropdown-item--danger" role="menuitem" type="button">Delete project</button>
Disabled item
<button class="dropdown-item is-disabled" role="menuitem" type="button" disabled aria-disabled="true">
Save as...
</button>
When to use what
| Pattern | When to use | Example |
|---|---|---|
| Icon-left | Action verbs, the icon reinforces what the action does | Edit, Download, Delete, Settings |
| Icon-right () | Trailing metadata: keyboard shortcuts, badges, status | Undo Ctrl+Z, Status Active |
| No icon | Simple value selection, the text is self-explanatory | Role names, client names, sizes |
| Avatar | User identification, profile menus | Account dropdown |
| Description () | Items that need explanation | "From template. Choose from pre-built..." |
| Section label () | Grouping related items under a heading | "Switch Role", "Danger zone" |
| Divider () | Separating logical groups | Between actions and danger items |
JavaScript
Include assets/js/dropdown.js on any page. It auto-initialises all elements, no setup needed.
<script src="/assets/js/dropdown.js"></script>
Clicking a toggles on the parent . Clicking outside or pressing Escape closes all open dropdowns.
Keyboard interactions
| Key | Action |
|---|---|
Enter / Space |
Opens the dropdown (on trigger), activates item (on item) |
ArrowDown |
Moves focus to the next item |
ArrowUp |
Moves focus to the previous item |
Escape |
Closes the dropdown and returns focus to the trigger |
Tab |
Moves focus out of the dropdown |
Accessibility
- Trigger:
aria-haspopup="true",aria-expanded="false"(JS updates to"true"on open) - Icon-only triggers: add
aria-labeldescribing the action - Menu:
role="menu" - Items:
role="menuitem"on buttons, or just<a>for link items - Dividers:
role="separator" - Disabled items:
disabledattribute +aria-disabled="true"
Structure reference
| Element | Class | Purpose |
|---|---|---|
| Container | Positioning context | |
| Trigger | Clickable element that opens the menu | |
| Chevron | Rotating arrow indicator (on trigger) | |
| Menu | The panel that appears | |
| Menu (right) | .dropdown-menu .is-right |
Right-aligned from trigger |
| Item | Clickable row | |
| Item (danger) | .dropdown-item .dropdown-item--danger |
Destructive action |
| Item (disabled) | .dropdown-item .is-disabled |
Unavailable action |
| Trailing content | Right-aligned metadata inside an item | |
| Description | Supporting text under item label | |
| Label | Non-interactive section header | |
| Divider | Separator line between groups |
Usage rules
Do:
- Use dropdowns for contextual actions and selections
- Group related items with labels and dividers
- Use icon-left for actions, icon-right for metadata
- Add
aria-labelon icon-only triggers - Use near the right viewport edge
Don't:
- Don't use dropdowns for primary navigation, use tabs or links
- Don't nest dropdowns inside dropdowns
- Don't use dropdowns for form field selection, use
<select>instead - Don't put more than 10 items in a single dropdown, break into sections or use a different pattern
CSS reference
This section documents how the component is built. For usage, see the sections above.
Tokens
| Token | Default | What it controls |
|---|---|---|
| Menu background | ||
| Menu and divider border | ||
| Item hover background |
Selectors
| Selector | Purpose |
|---|---|
Positioning context (position: relative) |
|
| Clickable trigger: flex layout, hover styles | |
.dropdown-trigger:hover |
Trigger hover state |
.dropdown-trigger .svg-icn |
Icon sizing inside trigger |
.dropdown.is-open > .dropdown-trigger |
Active trigger state when menu is open |
Rotating arrow indicator, transitions transform |
|
.dropdown.is-open .dropdown-chevron |
Chevron rotated 180deg when open |
| Absolutely positioned menu panel, hidden by default | |
.dropdown-menu.is-right |
Right-aligned menu positioning |
.dropdown.is-open .dropdown-menu |
Visible menu state |
| Clickable row: padding, hover background | |
.dropdown-item:hover |
Item hover, uses |
.dropdown-item:focus-visible |
Item focus ring |
.dropdown-item .svg-icn |
Icon sizing inside items |
.dropdown-item.is-disabled |
Disabled item: reduced opacity, no pointer events |
| Destructive action, danger colour | |
.dropdown-item--danger:hover |
Danger item hover |
| Separator line between groups | |
| Non-interactive section header | |
| Supporting text below item label | |
| Right-aligned trailing content inside an item |