Dropdowns
Anchored menus for actions and selections.
Setup
Dropdown styles are included in Manifest CSS or a standalone stylesheet, both referencing theme variables.
Dropdown functionality is included in manifest.js with all core plugins, or it can be selectively loaded.
<!-- Manifest CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/mnfst@latest/lib/manifest.min.css" />
<!-- Manifest JS -->
<script src="https://cdn.jsdelivr.net/npm/mnfst@latest/lib/manifest.min.js"></script>
For OS dropdowns, see selects.
Default
Dropdowns use the <menu> element as a popover. The <button> that opens the dropdown requires the x-dropdown attribute, matching the menu ID.
<button x-dropdown="basic-menu">Open Menu</button>
<menu popover id="basic-menu">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</menu>
Hover
Add the hover modifier to x-dropdown for mouseover dropdowns:
<button x-dropdown.hover="hover-menu">Hover Me</button>
<menu popover id="hover-menu">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</menu>
Hover dropdowns include a small delay to prevent accidental auto-close if the mouse briefly leaves the trigger or menu area.
Context Menu
Add the context modifier to x-dropdown for right-click dropdowns. The menu appears at the cursor position, replacing the browser's native context menu on the trigger element.
<div x-dropdown.context="context-menu">Right-click this area</div>
<menu popover id="context-menu">
<li>Cut</li>
<li>Copy</li>
<li>Paste</li>
</menu>
The trigger element does not need to be a <button> since the menu is opened programmatically on right-click rather than via the popovertarget attribute's click-to-toggle behavior. The menu still uses the Popover API for rendering and stacking.
Auto-Close
Dropdowns stay open when an item is clicked, so menus built around checkboxes, switches and inputs keep working. Add the close attribute to an individual item to dismiss the menu when that item is activated:
<button x-dropdown="autoclose-menu">Actions</button>
<menu popover id="autoclose-menu">
<li close>Duplicate</li>
<a href="#" close>Settings</a>
<li>Stays open</li>
</menu>
Add the close modifier to x-dropdown when every item should dismiss the menu, as in a select-like list of choices:
<button x-dropdown.close="autoclose-all">Select One</button>
<menu popover id="autoclose-all">
<li>Rename</li>
<li>Archive</li>
<li>Delete</li>
<hr>
<label><input type="checkbox" /><span>Stays open</span></label>
<li keep-open>Also stays open</li>
</menu>
Embedded controls are excluded from the close modifier, so a row that is — or contains — an input, textarea, select, switch, combobox, nested button or submenu trigger leaves the menu open. A <button> or <a> used as the row itself counts as an item and closes. Add keep-open to exclude any other row.
Selecting an item inside a nested menu closes its parent menus as well, and keyboard activation returns focus to the trigger.
Nesting
Create multi-level navigation menus with nested dropdowns.
<button x-dropdown="nested-menu">Main Menu</button>
<!-- Main Menu -->
<menu popover id="nested-menu">
<li>Item 1</li>
<li>Item 2</li>
<button x-dropdown="submenu-1"><span>Submenu</span><span x-icon="lucide:chevron-right" class="trailing"></span></button>
<li>Item 4</li>
<!-- Submenu 1 -->
<menu popover id="submenu-1">
<li>Item 1</li>
<li>Item 2</li>
<button x-dropdown.hover="submenu-2"><span>Hover Submenu</span><span x-icon="lucide:chevron-right" class="trailing"></span></button>
<!-- Submenu 2 -->
<menu popover id="submenu-2">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</menu>
</menu>
</menu>
Nested dropdowns automatically position themselves to avoid overlapping and maintain proper navigation flow.
Positioning
Menus have utility classes like top and bottom to position them in relation to their trigger buttons. If no class is set, menus default to bottom-start, or end-start if nested.
Examples
<!-- Top -->
<menu popover id="..." class="top">...</menu>
<!-- Bottom with start alignment -->
<menu popover id="..." class="bottom-start">...</menu>
<!-- Start with top alignment -->
<menu popover id="..." class="start-top">...</menu>
<!-- Top start corner (either version works) -->
<menu popover id="..." class="top-start-corner">...</menu>
<menu popover id="..." class="start-top-corner">...</menu>
Regardless of a set class, dropdowns overflowing the viewport will attempt to stay onscreen with default fallback positions.
Templating
HTML IDs must identify single elements on a page, and generating multiple dropdowns in a template loop requires each dropdown be assigned a unique ID. These can be generated with Alpine using template literals like ${i}.
<template x-for="i in 3" :key="i">
<!-- Multiple elements need to be wrapped in a container, since template tags only recognize their first child. -->
<div>
<!-- Button template -->
<button x-dropdown="`template-menu-${i}`" x-text="`Menu ${i}`"></button>
<!-- Menu template -->
<menu popover :id="`template-menu-${i}`">
<li>Item 1</li>
<li>Item 2</li>
</menu>
</div>
</template>
Content
Use <li> elements for generic options in a dropdown, with Alpine's @click directive giving them utility. A variety of other elements support additional dropdown content needs.
<button x-dropdown="content-menu"><span>Dropdown</span><span x-icon="lucide:chevron-down" class="trailing"></span></button>
<menu popover id="content-menu" class="w-60 max-h-160">
<small>List Items</small>
<li @click="alert('Hello world')">Do Something</li>
<li><span x-icon="lucide:house"></span><span>Icon</span></li>
<li><span>Trailing</span><kbd class="trailing">⌘</kbd><kbd>D</kbd></li>
<li class="brand">Brand</li>
<li class="accent">Accent</li>
<li class="negative">Negative</li>
<hr>
<small>Links</small>
<a href="#"><span x-icon="lucide:home"></span>Home</a>
<a href="#"><span x-icon="lucide:settings"></span><span>Settings</span><span x-icon="lucide:external-link" class="trailing"></span></a>
<hr>
<small>Buttons</small>
<button><span x-icon="lucide:copy"></span><span>Copy</span></button>
<button><span x-icon="lucide:edit"></span><span>Edit</span></button>
<hr>
<small>Checkboxes</small>
<label><input type="checkbox" /><span>Lorem ipsum dolor sit amet</span></label>
<label><input type="checkbox" /><span>Consectetur adipiscing elit</span></label>
<hr>
<small>Radios</small>
<label><input type="radio" id="option-a" name="group-preview" checked /><span>Option A</span></label>
<label><input type="radio" id="option-b" name="group-preview" /><span>Option B</span></label>
<label><input type="radio" id="option-c" name="group-preview" /><span>Option C</span></label>
<hr>
<small>Switches</small>
<label for="switch1">Switch 1<input id="switch1" role="switch" type="checkbox" checked /></label>
<label for="switch2">Switch 2<input id="switch2" role="switch" type="checkbox"/></label>
<hr>
<small>Text Inputs</small>
<input placeholder="Text input" />
<textarea placeholder="Textarea"></textarea>
</menu>
Use the following elements as direct children of a dropdown <menu>:
<small>- Group titles<hr>- Dividers<li>- Generic options<button>- Button options (i.e. triggers for sub-dropdowns)<a>- Links<label>- Wrappers for radios, checkboxes, and switches<input>- Single line text fields<textarea>- Multi-line text fields
And use <span> within applicable elements above for icons, truncating text with ellipsis, and trailing content.
Closed Menus Cost Nothing
A closed menu's contents are not initialized until it opens. Nothing inside it runs while it is closed, so a page can hold hundreds of menus for free.
During idle time, Manifest warms the menus the visitor is likely to open next, so opening is instant. A menu that has not been warmed renders when it opens, and a menu opened once stays ready.
Three optional knobs on the <menu> element:
x-defer.priority="1"— warm this menu first (a lower number is warmed earlier). Use on the one or two menus people open most.x-defer.off— keep a menu eager. Only for menus whose contents must exist while closed.x-defer.discard— throw the contents away when the menu closes, for large, rarely reopened menus.
<menu popover id="account-menu" x-defer.priority="1">
<li>Profile</li>
<li>Sign out</li>
</menu>
The modifier is part of the attribute name and the number is its value: x-defer.priority="1". Writing x-defer="priority:1" does nothing.
<div x-data="{ countries: /* 300 entries */ }">
<button x-dropdown="country-menu">Country</button>
<menu popover id="country-menu">
<div x-virtual class="h-64">
<template x-for="country in countries" :key="country.id">
<li x-text="country.name"></li>
</template>
</div>
</menu>
</div>
Three hundred rows are in the menu, but only the visible ones are rendered, and none of them exist until the menu opens.
Styles
Theme
Default dropdowns use the following theme variables:
| Variable | Purpose |
|---|---|
--color-popover-surface |
Menu background color |
--color-content-stark |
Menu text color |
--color-field-surface |
Hover background color |
--color-content-neutral |
Section title color |
--color-line |
Divider color |
--spacing-popover-offset |
Offset from trigger element |
Tailwind CSS
If using Tailwind, individual menus can be customized with utility classes. Menus taller than a max height will vertically scroll.
<button x-dropdown="menu-wide-preview">Offset & Widen</button>
<menu popover id="menu-wide-preview" class="w-100 !m-6">
<li>Lorem ipsum dolor sit amet</li>
<li>Consectetur adipiscing elit</li>
<li>Sed do eiusmod tempor incididunt</li>
</menu>
Customization
Modify base dropdown styles with custom CSS for the menu[popover] selector.
menu[popover] {
background-color: #f0f8ff;
border: 2px solid #3b82f6;
border-radius: 12px;
box-shadow: 0 8px 25px rgba(59, 130, 246, 0.3);
/* Any relevant options */
& :where(li, a, button, label) {
color: #1e40af;
border-radius: 8px;
&:hover {
background-color: #dbeafe;
}
}
}
Article does not exist
There is no documentation at this path.