<div class="dropdown-menu">
<button type="button" id="demo-dropdown-menu-trigger" popovertarget="demo-dropdown-menu" aria-haspopup="menu" aria-controls="demo-dropdown-menu-menu" aria-expanded="false" class="btn-outline">Open</button>
<div popover class="popover p-1 min-w-56" id="demo-dropdown-menu">
<nav role="menu" id="demo-dropdown-menu-menu" aria-labelledby="demo-dropdown-menu-trigger">
<div role="group" aria-labelledby="account-options">
<span id="account-options" role="heading">My Account</span>
<button type="button" role="menuitem">
Profile
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
<button type="button" role="menuitem">
Billing
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
</button>
<button type="button" role="menuitem">
Settings
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
</button>
<button type="button" role="menuitem">
Keyboard shortcuts
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘K</span>
</button>
</div>
<hr role="separator" />
<button type="button" role="menuitem">GitHub</button>
<button type="button" role="menuitem">Support</button>
<button type="button" role="menuitem" disabled>API</button>
<hr role="separator" />
<button type="button" role="menuitem">
Logout
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
</nav>
</div>
</div>
Usage
HTML + JavaScript
Step 1: Include the JavaScript files
Include the dropdown-menu.js
file. It is recommended to also include the CSS anchor positioning polyfill to support older browsers. Add this to the <head>
of your page:
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@beta/dist/js/dropdown-menu.min.js" defer></script>
<script type="module">
if (!("anchorName" in document.documentElement.style)) {
import("https://cdn.jsdelivr.net/npm/basecoat-css@beta/dist/js/css-anchor-positioning.min.js");
}
</script>
Step 2: Add your dropdown menu HTML
<div class="dropdown-menu">
<button type="button" id="demo-dropdown-menu-trigger" popovertarget="demo-dropdown-menu" aria-haspopup="menu" aria-controls="demo-dropdown-menu-menu" aria-expanded="false" class="btn-outline">Open</button>
<div popover class="popover p-1 min-w-56" id="demo-dropdown-menu">
<nav role="menu" id="demo-dropdown-menu-menu" aria-labelledby="demo-dropdown-menu-trigger">
<div role="group" aria-labelledby="account-options">
<span id="account-options" role="heading">My Account</span>
<button type="button" role="menuitem">
Profile
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
<button type="button" role="menuitem">
Billing
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
</button>
<button type="button" role="menuitem">
Settings
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
</button>
<button type="button" role="menuitem">
Keyboard shortcuts
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘K</span>
</button>
</div>
<hr role="separator" />
<button type="button" role="menuitem">GitHub</button>
<button type="button" role="menuitem">Support</button>
<button type="button" role="menuitem" disabled>API</button>
<hr role="separator" />
<button type="button" role="menuitem">
Logout
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
</nav>
</div>
</div>
HTML structure
<div class="dropdown-menu">
- Wraps around the entire component.
<button type="button" popovertarget="{ POPOVER_ID }">
-
The trigger to open the popover, can also have the following attributes:
id="{BUTTON_ID}"
: linked to by thearia-labelledby
attribute of the listbox.aria-haspopup="menu"
: indicates that the button opens a menu.aria-controls="{ MENU_ID }"
: points to the menu's id.aria-expanded="false"
: tracks the popover's state.
<div popover class="popover" id="{ POPOVER_ID }">
- As with the Popover component, you can set up the side and alignment of the popover using the
data-side
anddata-align
attributes.<div role="menu">
- The menu containing the options. Should have the following attributes:
id="{ MENU_ID }"
: refered to by thearia-controls
attribute of the trigger.aria-labelledby="{ BUTTON_ID }"
: linked to by the button'sid
attribute.
<button role="menuitem">
- Menu item.
<button role="menuitemcheckbox">
- Menu item with a checkbox.
<button role="menuitemradio">
- Menu item with a radio button.
<hr role="separator">
Optional- Separator between groups/options.
<div role="group">
Optional- Group of options, can have a
aria-labelledby
attribute to link to a heading. <span role="heading">
- Group heading, must have an
id
attribute if you use thearia-labelledby
attribute on the group.
Jinja and Nunjucks
You can use the dropdown_menu()
Nunjucks or Jinja macro for this component.
{% call dropdown_menu(
id="dropdown-menu",
trigger="Open",
trigger_attrs={"class": "btn-outline"},
content_attrs={"class": "min-w-56"},
register_on=["alpine:init", "htmx:afterSwap"]
) %}
<div role="group" aria-labelledby="account-options">
<span id="account-options" role="heading">My Account</span>
<button type="button" role="menuitem">
Profile
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
<button type="button" role="menuitem">
Billing
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
</button>
<button type="button" role="menuitem">
Settings
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
</button>
<button type="button" role="menuitem">
Keyboard shortcuts
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘K</span>
</button>
</div>
<hr role="separator">
<button type="button" role="menuitem">
GitHub
</button>
<button type="button" role="menuitem">
Support
</button>
<button type="button" role="menuitem" disabled>
API
</button>
<hr role="separator">
<button type="button" role="menuitem">
Logout
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
{% endcall %}
Examples
Checkboxes
<div class="dropdown-menu">
<button type="button" id="dropdown-menu-checkboxes-trigger" popovertarget="dropdown-menu-checkboxes" aria-haspopup="menu" aria-controls="dropdown-menu-checkboxes-menu" aria-expanded="false" class="btn-outline">Open</button>
<div popover class="popover p-1" id="dropdown-menu-checkboxes">
<nav role="menu" id="dropdown-menu-checkboxes-menu" aria-labelledby="dropdown-menu-checkboxes-trigger">
<div role="group" aria-labelledby="account-options">
<span id="account-options" role="heading">Account Options</span>
<button type="button" role="menuitem">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" 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
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
<button type="button" role="menuitem">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" 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
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
</button>
<button type="button" role="menuitem">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" />
<circle cx="12" cy="12" r="3" />
</svg>
Settings
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
</button>
</div>
<hr role="separator" />
<div role="group" aria-labelledby="appearance-options">
<span id="appearance-options" role="heading">Appearance</span>
<button type="button" role="menuitemcheckbox" aria-checked="true" class="group" x-data="{ checked: true }" @click="checked = !checked" :aria-checked="checked">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="invisible group-aria-checked:visible" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg>
Status Bar
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
<button type="button" role="menuitemcheckbox" aria-checked="false" class="group" disabled x-data="{ checked: false }" @click="checked = !checked" :aria-checked="checked">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="invisible group-aria-checked:visible" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg>
Activity Bar
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
</button>
<button type="button" role="menuitemcheckbox" aria-checked="false" class="group" x-data="{ checked: false }" @click="checked = !checked" :aria-checked="checked">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="invisible group-aria-checked:visible" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5" /></svg>
Panel
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
</button>
</div>
<hr role="separator" />
<button type="button" role="menuitem">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
<polyline points="16 17 21 12 16 7" />
<line x1="21" x2="9" y1="12" y2="12" />
</svg>
Logout
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
</nav>
</div>
</div>
Radio Group
<div class="dropdown-menu">
<button type="button" id="dropdown-menu-radio-group-trigger" popovertarget="dropdown-menu-radio-group" aria-haspopup="menu" aria-controls="dropdown-menu-radio-group-menu" aria-expanded="false" class="btn-outline">Open</button>
<div popover class="popover p-1 min-w-56" id="dropdown-menu-radio-group">
<nav role="menu" id="dropdown-menu-radio-group-menu" aria-labelledby="dropdown-menu-radio-group-trigger">
<div role="group" aria-labelledby="position-options" x-data="{ checked: 'bottom' }">
<span id="position-options" role="heading">Panel Position</span>
<hr role="separator" />
<button type="button" role="menuitemradio" aria-checked="false" class="group" @click="checked = 'top'" :aria-checked="checked == 'top'">
<div class="size-4 flex items-center justify-center">
<div class="size-2 rounded-full bg-foreground invisible group-aria-checked:visible" aria-hidden="true" , focusable="false"></div>
</div>
Status Bar
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⇧⌘P</span>
</button>
<button type="button" role="menuitemradio" aria-checked="false" class="group" @click="checked = 'bottom'" :aria-checked="checked == 'bottom'">
<div class="size-4 flex items-center justify-center">
<div class="size-2 rounded-full bg-foreground invisible group-aria-checked:visible" aria-hidden="true" , focusable="false"></div>
</div>
Activity Bar
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘B</span>
</button>
<button type="button" role="menuitemradio" aria-checked="false" class="group" @click="checked = 'right'" :aria-checked="checked == 'right'">
<div class="size-4 flex items-center justify-center">
<div class="size-2 rounded-full bg-foreground invisible group-aria-checked:visible" aria-hidden="true" , focusable="false"></div>
</div>
Panel
<span class="text-muted-foreground ml-auto text-xs tracking-widest">⌘S</span>
</button>
</div>
</nav>
</div>
</div>