Dropdown
A menu of actions anchored to a trigger, built with the native
popover API and a <menu>.
Default
<button popovertarget="my-dropdown">Actions</button>
<div id="my-dropdown" popover>
<menu>
<li><button class="ghost">Edit</button></li>
<li><button class="ghost">Duplicate</button></li>
<li><button class="ghost">Share</button></li>
<li><button class="ghost">Archive</button></li>
</menu>
</div>
With separator
Use an <hr> inside a <li> to
visually group actions.
<button popovertarget="my-dropdown">Actions</button>
<div id="my-dropdown" popover>
<menu>
<li><button class="ghost">Edit</button></li>
<li><button class="ghost">Duplicate</button></li>
<li><button class="ghost">Share</button></li>
<li><hr /></li>
<li><button class="ghost destructive">Delete</button></li>
</menu>
</div>
With section labels
A <li> whose only child is a text-only
<small> is automatically styled as a section label.
No extra class needed.
<div id="my-dropdown" popover>
<menu>
<li><small>Actions</small></li>
<li><button class="ghost">New File</button></li>
<li><button class="ghost">New Folder</button></li>
<li><hr /></li>
<li><small>Danger zone</small></li>
<li><button class="ghost destructive">Delete</button></li>
</menu>
</div>
With radios
Radio inputs work naturally inside a dropdown — the checked state is preserved between opens and a checkmark appears via CSS. The popover stays open so the user can see their selection before dismissing.
<button popovertarget="my-dropdown">Sort by</button>
<div id="my-dropdown" popover>
<menu>
<li>
<label>
<input type="radio" name="sort" value="newest" checked /> Newest
</label>
</li>
<li>
<label> <input type="radio" name="sort" value="oldest" /> Oldest </label>
</li>
<li>
<label> <input type="radio" name="sort" value="name" /> Name </label>
</li>
<li>
<label> <input type="radio" name="sort" value="size" /> Size </label>
</li>
</menu>
</div>
With checkboxes
Checkboxes allow multiple selections. An empty square indicates each item is toggleable; a filled square with checkmark appears when selected.
<button popovertarget="my-dropdown">Columns</button>
<div id="my-dropdown" popover>
<menu>
<li>
<label>
<input type="checkbox" name="col" value="name" checked /> Name
</label>
</li>
<li>
<label>
<input type="checkbox" name="col" value="size" checked /> Size
</label>
</li>
<li>
<label> <input type="checkbox" name="col" value="type" /> Type </label>
</li>
<li>
<label>
<input type="checkbox" name="col" value="modified" /> Modified
</label>
</li>
</menu>
</div>
Custom select
Use radio inputs inside <label>s to build a styled
select. A checkmark appears on the chosen option via CSS. A small
script updates the trigger text and closes the dropdown on pick.
<button
popovertarget="my-select"
style="min-width: 10rem; justify-content: space-between"
>
<span>Choose a fruit</span>
<svg><!-- chevron --></svg>
</button>
<div
id="my-select"
popover
onchange="
document.querySelector(`[popovertarget=${this.id}] span`).textContent =
event.target.closest('label').textContent;
this.hidePopover();
"
>
<menu>
<li>
<label> <input type="radio" name="fruit" /> Apple </label>
</li>
<li>
<label> <input type="radio" name="fruit" /> Banana </label>
</li>
<li>
<label> <input type="radio" name="fruit" /> Cherry </label>
</li>
</menu>
</div>
In a form
Wrap the trigger and popover in a <form> to
participate in form submission. The change event bubbles
up so you can handle it on the form.
<form onchange="alert('Selected: ' + event.target.value)">
<button
type="button"
popovertarget="my-select"
style="min-width: 10rem; justify-content: space-between"
>
<span>Choose a color</span>
<svg><!-- chevron --></svg>
</button>
<div
id="my-select"
popover
onchange="
document.querySelector(`[popovertarget=${this.id}] span`).textContent =
event.target.closest('label').textContent;
this.hidePopover();
"
>
<menu>
<li>
<label> <input type="radio" name="color" value="red" /> Red </label>
</li>
<li>
<label> <input type="radio" name="color" value="green" /> Green </label>
</li>
<li>
<label> <input type="radio" name="color" value="blue" /> Blue </label>
</li>
</menu>
</div>
</form>