Menu
A dropdown menu with full keyboard support, typeahead, and positioning.
html
<div data-controller="zag-menu" class="relative inline-block text-left">
<button
data-part="trigger"
class="border-input bg-popover text-foreground hover:bg-accent focus-visible:ring-ring data-[state=open]:bg-accent inline-flex items-center gap-2 rounded-lg border px-4 py-2 text-sm font-medium shadow-sm transition focus:outline-none focus-visible:ring-2"
>
Actions
<span
data-part="indicator"
class="text-muted-foreground transition-transform data-[state=open]:rotate-180"
aria-hidden="true"
>▾</span
>
</button>
<div data-part="positioner">
<div
data-part="content"
hidden
class="border-border bg-popover z-50 min-w-44 rounded-lg border p-1 shadow-lg focus:outline-none"
>
<button
data-part="item"
data-value="edit"
class="text-foreground data-[highlighted]:bg-primary data-[highlighted]:text-primary-foreground flex w-full cursor-pointer items-center rounded-md px-3 py-2 text-sm"
>
Edit
</button>
<button
data-part="item"
data-value="duplicate"
class="text-foreground data-[highlighted]:bg-primary data-[highlighted]:text-primary-foreground flex w-full cursor-pointer items-center rounded-md px-3 py-2 text-sm"
>
Duplicate
</button>
<hr data-part="separator" class="border-border my-1" />
<button
data-part="item"
data-value="delete"
data-disabled
class="text-destructive data-[highlighted]:bg-destructive flex w-full items-center rounded-md px-3 py-2 text-sm data-[disabled]:cursor-not-allowed data-[highlighted]:text-white data-[disabled]:opacity-40"
>
Delete
</button>
</div>
</div>
</div>Parts
trigger, indicator, positioner, content, item, separator, arrow, arrow-tip.
Each item carries a data-value; add data-disabled to disable one.
Values
| Attribute | Type | Default | Description |
|---|---|---|---|
data-zag-menu-placement-value | String | "bottom-start" | Popper placement of the content. |
data-zag-menu-gutter-value | Number | 8 | Gap (px) between trigger and content. |
data-zag-menu-close-on-select-value | Boolean | true | Close the menu after choosing an item. |
data-zag-menu-loop-focus-value | Boolean | false | Wrap keyboard focus at the ends. |
Events
Emits zag-menu:select — a CustomEvent whose detail is { value } for the chosen item.
js
element.addEventListener("zag-menu:select", (e) => console.log(e.detail.value))Programmatic control
From another Stimulus controller (via outlets or getControllerForElementAndIdentifier): open(), close(), isOpen.