Wraps a toggle, menu, and items into a single dropdown unit. Uses the native Popover API for light-dismiss (clicking outside closes the menu automatically).
<!-- Basic dropdown -->
<div dropdown>
<button dropdown-toggle>Options</button>
<ul dropdown-menu>
<li dropdown-item>Edit</li>
<li dropdown-item>Duplicate</li>
<li dropdown-item>Delete</li>
</ul>
</div>
<!-- Positioned to the right, aligned to end -->
<div dropdown dropdown-position="right" dropdown-align="end">
<button dropdown-toggle>More</button>
<ul dropdown-menu>
<li dropdown-item>Settings</li>
<li dropdown-item>Logout</li>
</ul>
</div>| Attribute | Type | Default | Description |
|---|---|---|---|
dropdown |
boolean attr | required | Marks the wrapper element |
dropdown-position |
"bottom" | "top" | "left" | "right" |
"bottom" |
Primary axis for menu placement |
dropdown-align |
"start" | "end" |
"start" |
Cross-axis alignment of the menu relative to the toggle |
The menu is positioned with position: fixed and automatically flips to the opposite side when it would overflow the viewport.
Note: Because dropdown menus use
position: fixedwith viewport-absolute coordinates, they escape parentoverflow: hiddencontainers. This means dropdowns inside scrollable or clipped elements will still display correctly.
The element that opens/closes the dropdown menu on click. Must be inside a [dropdown] container.
<div dropdown>
<button dropdown-toggle>Click me</button>
<ul dropdown-menu>
<li dropdown-item>Option A</li>
<li dropdown-item>Option B</li>
</ul>
</div>The toggle automatically receives:
aria-haspopup="menu"aria-expanded="true"/"false"(updated on open/close)aria-controlslinked to the menu'sid
The menu panel that appears when the toggle is activated. Uses popover="auto" for native light-dismiss behavior.
<div dropdown>
<button dropdown-toggle>Actions</button>
<ul dropdown-menu>
<li dropdown-item>Cut</li>
<li dropdown-item>Copy</li>
<li dropdown-item>Paste</li>
</ul>
</div>The menu automatically receives:
popover="auto"(native Popover API)role="menu"- A unique
id(auto-generated if not provided) - Class
.nojs-dropdown-menu
An actionable item inside the dropdown menu. Supports keyboard navigation, disabled state, and automatic ARIA attributes.
<!-- With disabled items -->
<div dropdown>
<button dropdown-toggle>File</button>
<ul dropdown-menu>
<li dropdown-item>New</li>
<li dropdown-item>Open</li>
<li dropdown-item disabled>Save (read-only)</li>
<li dropdown-item>Export</li>
</ul>
</div>
<!-- With links -->
<div dropdown>
<button dropdown-toggle>Navigate</button>
<ul dropdown-menu>
<a dropdown-item href="/dashboard">Dashboard</a>
<a dropdown-item href="/settings">Settings</a>
<a dropdown-item href="/help">Help</a>
</ul>
</div>| Attribute | Type | Default | Description |
|---|---|---|---|
dropdown-item |
boolean attr | required | Marks the element as a menu item |
disabled |
boolean attr | — | Disables the item (skipped during keyboard navigation) |
Each item automatically receives:
role="menuitem"tabindex="-1"- Class
.nojs-dropdown-item aria-disabled="true"whendisabledis present
| Key | On toggle | On item |
|---|---|---|
| Enter / Space | Opens menu, focuses first item | Activates item (click) |
| Arrow Down | Opens menu, focuses first item | Moves focus to next item (wraps to first) |
| Arrow Up | Opens menu, focuses last item | Moves focus to previous item (wraps to last) |
| Home | — | Moves focus to first item |
| End | — | Moves focus to last item |
| Escape | — | Closes menu, returns focus to toggle |
| Tab | — | Closes menu, returns focus to toggle |
Disabled items are skipped during arrow-key navigation.
No.JS automatically injects these classes:
| Class | When applied |
|---|---|
.nojs-dropdown-menu |
On the menu element ([dropdown-menu]) |
.nojs-dropdown-item |
On each item element ([dropdown-item]) |
.nojs-dropdown-item[aria-disabled="true"] |
On disabled items — pointer-events: none; opacity: 0.5 |
.nojs-dropdown-item:focus-visible |
On the currently focused item (for keyboard navigation styling) |
The menu uses position: fixed with z-index: 9999 and min-width: max-content. It repositions on scroll and resize while open.
No.JS automatically adds:
aria-haspopup="menu"on the togglearia-expanded="true/false"on the toggle (reflects open state)aria-controlslinking the toggle to the menurole="menu"on the menurole="menuitem"on each itemtabindex="-1"on items (roving focus via keyboard)aria-disabled="true"on disabled items- Focus is trapped within the menu while open — Escape or Tab returns focus to the toggle
Next: Toast Notifications →