Skip to content

Select

A custom, accessible dropdown select backed by a real hidden <select> for form submission. Options are authored as item parts carrying data-value; stimulus-zag builds the Zag collection from them and stamps matching <option>s into the hidden select.

html
<div
  data-controller="zag-select"
  data-part="root"
  data-zag-select-name-value="fruit"
  class="relative max-w-xs"
>
  <button
    data-part="trigger"
    class="border-input bg-popover hover:bg-accent focus-visible:ring-ring flex w-full items-center justify-between gap-2 rounded-lg border px-4 py-2 text-sm shadow-sm focus:outline-none focus-visible:ring-2"
  >
    <span data-part="value-text" class="text-foreground">Pick a fruit</span>
    <span
      data-part="indicator"
      class="text-muted-foreground transition-transform data-[state=open]:rotate-180"
      >▾</span
    >
  </button>
  <div data-part="positioner">
    <ul
      data-part="content"
      hidden
      class="border-border bg-popover z-50 max-h-60 w-[var(--reference-width)] overflow-auto rounded-lg border p-1 shadow-lg focus:outline-none"
    >
      <li
        data-part="item"
        data-value="apple"
        class="data-[highlighted]:bg-primary data-[highlighted]:text-primary-foreground flex cursor-pointer items-center justify-between rounded-md px-3 py-2 text-sm"
      >
        <span data-part="item-text">Apple</span>
        <span data-part="item-indicator" hidden>✓</span>
      </li>
      <li
        data-part="item"
        data-value="banana"
        class="data-[highlighted]:bg-primary data-[highlighted]:text-primary-foreground flex cursor-pointer items-center justify-between rounded-md px-3 py-2 text-sm"
      >
        <span data-part="item-text">Banana</span>
        <span data-part="item-indicator" hidden>✓</span>
      </li>
      <li
        data-part="item"
        data-value="cherry"
        class="data-[highlighted]:bg-primary data-[highlighted]:text-primary-foreground flex cursor-pointer items-center justify-between rounded-md px-3 py-2 text-sm"
      >
        <span data-part="item-text">Cherry</span>
        <span data-part="item-indicator" hidden>✓</span>
      </li>
    </ul>
  </div>
  <select data-part="hidden-select" class="sr-only"></select>
</div>

Parts

root, label, control, trigger, value-text, indicator, clear-trigger, positioner, content, list, item, item-text, item-indicator, hidden-select.

Values

AttributeTypeDefaultDescription
data-zag-select-value-valueArray[]Selected value(s) by default (JSON).
data-zag-select-multiple-valueBooleanfalseAllow selecting multiple items.
data-zag-select-name-valueString""name of the hidden select.
data-zag-select-placement-valueString"bottom-start"Popper placement.
data-zag-select-close-on-select-valueBooleantrueClose after choosing (single).
data-zag-select-loop-focus-valueBooleanfalseWrap keyboard focus.
data-zag-select-disabled-valueBooleanfalseDisable the select.
data-zag-select-required-valueBooleanfalseMark the field required.
data-zag-select-invalid-valueBooleanfalseMark the field invalid.
data-zag-select-read-only-valueBooleanfalseRead-only.

Events

Emits zag-select:change ({ value, items }) and zag-select:open-change ({ open }).

Programmatic control

value (getter), valueAsString (getter), setValue(string[]), clear(), open(), close(), isOpen.