Select

Displays a list of options for the user to pick from—triggered by a button.

Usage

HTML

If you use a <select> element, just add the select class to it or have a parent with the form class (read more about form).

<select class="select w-[180px]">
  <optgroup label="Fruits">
    <option>Apple</option>
    <option>Banana</option>
    <option>Blueberry</option>
    <option>Grapes</option>
    <option>Pineapple</option>
</select>

HTML + Javascript

If you need to do more than what <select> allows (e.g. HTML options), you can use this component. It is structured as such:

  • A <div class="popover"> which wraps around the entire component and holds it state (e.g. open/close).
  • A <button> that acts as the trigger to open or close the popover.
  • A <div data-popover> that holds the content of the popover.
  • Inside of the <div data-popover> is a <nav role="listbox"> that contains a combination of:
    • <div role="option"> for the options with a data-value attribute.
    • <hr role="separator"> to display a horizontal separator.
    • <div role="group"> to group options.
    • <span role="heading"> for group headings.
  • An <input type="hidden"> to hold the value of the field (if needed).

As with the Popover component, you can set up a few additional options on the <div data-popover> element:

  • data-side can be set to top, bottom, left, or right to change the side of the popover.
  • data-align can be set to start, center, or end to change the alignment of the popover.

You can include the Javascript code provided below, load it as an individual file or use the CLI. Some Alpine.js properties are also required on certain elements (e.g. x-bind, x-data, @click).

<div class="popover" x-data="select('select-js', '')" @click.away="open = false">
  <button type="button" aria-haspopup="listbox" aria-expanded="false" x-bind="$trigger" class="btn-outline justify-between font-normal w-[180px]">
    <div x-html="selectedLabel" class="flex items-center gap-x-2"></div>

    <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="lucide lucide-chevron-down-icon lucide-chevron-down text-muted-foreground opacity-50 shrink-0"><path d="m6 9 6 6 6-6" /></svg>
  </button>
  <div data-popover aria-hidden="true" x-bind="$content">
    <div role="listbox" aria-orientation="vertical">
      <div role="group" aria-labelledby="fruit-options-label">
        <span id="fruit-options-label" role="heading">Fruits</span>
        <div role="option" data-value="apple">Apple</div>
        <div role="option" data-value="banana">Banana</div>
        <div role="option" data-value="blueberry">Blueberry</div>
        <div role="option" data-value="pineapple">Grapes</div>
        <div role="option" data-value="pineapple">Pineapple</div>
      </div>
    </div>
  </div>

  <input type="hidden" name="select-js" x-model="selectedValue" />
</div>

The component will dispatch a select:change event when a value is selected, along with the value and label of the selected option in the detail object.

Jinja and Nunjucks

You can use the dropdown_menu() Nunjucks or Jinja macro for this component.

{% call select(name="select-js") %}
<div role="group" aria-labelledby="fruit-options-label">
  <span id="fruit-options-label" role="heading">Fruits</span>
  <div role="option" data-value="apple">Apple</div>
  <div role="option" data-value="banana">Banana</div>
  <div role="option" data-value="blueberry">Blueberry</div>
  <div role="option" data-value="pineapple">Grapes</div>
  <div role="option" data-value="pineapple">Pineapple</div>
</div>
{% endcall %}

Examples

Scrollable

Disabled

With icon