0.0.3

Listbox

A pure vanilla JS implementation of Zag JS Listbox Opens in a new window


Anatomy

The Listbox component consists of the following data-part

root label content item item-group item-group-label

It can include multiple item, item-group and item-group-label parts.

data-value is required on all item parts

  • Item A
  • Item B
  • Item C
  • Item D
<div class="listbox listbox-js">
                  <div data-part="root">
                  <label data-part="label">Listbox Label</label>
                  <ul data-part="content">
                  <li data-part="item" data-value="a" data-label="item-a">
                  <span data-part="item-text" data-value="a" data-label="item-a">
                  Item A
                  </span>
                  <span data-part="item-indicator" data-value="a" data-label="item-a">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="b" data-label="item-b">
                  <span data-part="item-text" data-value="b" data-label="item-b">
                  Item B
                  </span>
                  <span data-part="item-indicator" data-value="b" data-label="item-b">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="c" data-label="item-c">
                  <span data-part="item-text" data-value="c" data-label="item-c">
                  Item C
                  </span>
                  <span data-part="item-indicator" data-value="c" data-label="item-c">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="d" data-label="item-d">
                  <span data-part="item-text" data-value="d" data-label="item-d">
                  Item D
                  </span>
                  <span data-part="item-indicator" data-value="d" data-label="item-d">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </ul>
                  </div>
                  </div>

Group Items

The Listbox items can be grouped with a label to identify each group

Please note you must provide and id to item-group and item-group-label and not a value

    Group Label
  • Item A
  • Item B
  • Group Label
  • Item C
  • Item D
<div class="listbox listbox-js">
                  <div data-part="root">
                  <label data-part="label">Listbox Label</label>
                  <ul data-part="content">
                  <div data-part="item-group-label" data-id="group">Group Label</div>
                  <div data-part="item-group" data-id="group">
                  <li data-part="item" data-value="a" data-label="item-a">
                  <span data-part="item-text" data-value="a" data-label="item-a">
                  Item A
                  </span>
                  <span data-part="item-indicator" data-value="a" data-label="item-a">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="b" data-label="item-b">
                  <span data-part="item-text" data-value="b" data-label="item-b">
                  Item B
                  </span>
                  <span data-part="item-indicator" data-value="b" data-label="item-b">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </div>
                  <div data-part="item-group-label" data-id="group-1">Group Label</div>
                  <div data-part="item-group" data-id="group-1">
                  <li data-part="item" data-value="c" data-label="item-c">
                  <span data-part="item-text" data-value="c" data-label="item-c">
                  Item C
                  </span>
                  <span data-part="item-indicator" data-value="c" data-label="item-c">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="d" data-label="item-d">
                  <span data-part="item-text" data-value="d" data-label="item-d">
                  Item D
                  </span>
                  <span data-part="item-indicator" data-value="d" data-label="item-d">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </div>
                  </ul>
                  </div>
                  </div>

Column Layout

The Listbox can use the grid layout by adding data-column-count

The column count is available as dynamic css variable--column-count which is used in the component css

  • Item A
  • Item B
  • Item C
  • Item D
<div class="listbox listbox-js">
                  <div data-part="root">
                  <label data-part="label">Listbox Label</label>
                  <ul data-part="content">
                  <div data-part="item-group-label" data-id="group">Group Label</div>
                  <div data-part="item-group" data-id="group">
                  <li data-part="item" data-value="a" data-label="item-a">
                  <span data-part="item-text" data-value="a" data-label="item-a">
                  Item A
                  </span>
                  <span data-part="item-indicator" data-value="a" data-label="item-a">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="b" data-label="item-b">
                  <span data-part="item-text" data-value="b" data-label="item-b">
                  Item B
                  </span>
                  <span data-part="item-indicator" data-value="b" data-label="item-b">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </div>
                  <div data-part="item-group-label" data-id="group-1">Group Label</div>
                  <div data-part="item-group" data-id="group-1">
                  <li data-part="item" data-value="c" data-label="item-c">
                  <span data-part="item-text" data-value="c" data-label="item-c">
                  Item C
                  </span>
                  <span data-part="item-indicator" data-value="c" data-label="item-c">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="d" data-label="item-d">
                  <span data-part="item-text" data-value="d" data-label="item-d">
                  Item D
                  </span>
                  <span data-part="item-indicator" data-value="d" data-label="item-d">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </div>
                  </ul>
                  </div>
                  </div>

Data attributes

Each listbox can be set with different settings with the following data-attribute.

    Group Label
  • Item A
  • Item B
  • Group Label
  • Item C
  • Item D
<div class="listbox listbox-js" id="custom-listbox" data-default-highlighted-value="a" data-default-value="b,d" data-dir="ltr" data-orientation="vertical" data-select-on-highlight="true" data-loop-focus="false" data-typeahead="true" data-deselectable="true" data-disabled="false" data-disallow-select-all="false" data-selection-mode="extended">
                  <div data-part="root">
                  <label data-part="label">Listbox Label</label>
                  <ul data-part="content">
                  <div data-part="item-group-label" data-id="group">Group Label</div>
                  <div data-part="item-group" data-id="group">
                  <li data-part="item" data-value="a" data-label="item-a">
                  <span data-part="item-text" data-value="a" data-label="item-a">
                  Item A
                  </span>
                  <span data-part="item-indicator" data-value="a" data-label="item-a">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="b" data-label="item-b">
                  <span data-part="item-text" data-value="b" data-label="item-b">
                  Item B
                  </span>
                  <span data-part="item-indicator" data-value="b" data-label="item-b">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </div>
                  <div data-part="item-group-label" data-id="group-1">Group Label</div>
                  <div data-part="item-group" data-id="group-1">
                  <li data-part="item" data-value="c" data-label="item-c">
                  <span data-part="item-text" data-value="c" data-label="item-c">
                  Item C
                  </span>
                  <span data-part="item-indicator" data-value="c" data-label="item-c">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="d" data-label="item-d">
                  <span data-part="item-text" data-value="d" data-label="item-d">
                  Item D
                  </span>
                  <span data-part="item-indicator" data-value="d" data-label="item-d">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </div>
                  </ul>
                  </div>
                  </div>

Callbacks

Each Listbox component can receive callbacks that can be used to respond to user interaction with custom behavior.

You must add a custom id for the listbox and a event listener for your event name


                      document.getElementById("my-callback-listbox")
                      ?.addEventListener("my-callback-listbox-event", (event) => {
                        console.log("Received event:", (event as CustomEvent).detail);
                      });
                  
  • Item A
  • Item B
  • Item C
  • Item D
<div id="my-callback-listbox" class="listbox listbox-js" data-on-select="my-callback-listbox-event">
                  <div data-part="root">
                  <label data-part="label">Listbox Label</label>
                  <ul data-part="content">
                  <li data-part="item" data-value="a" data-label="item-a">
                  <span data-part="item-text" data-value="a" data-label="item-a">
                  Item A
                  </span>
                  <span data-part="item-indicator" data-value="a" data-label="item-a">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="b" data-label="item-b">
                  <span data-part="item-text" data-value="b" data-label="item-b">
                  Item B
                  </span>
                  <span data-part="item-indicator" data-value="b" data-label="item-b">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="c" data-label="item-c">
                  <span data-part="item-text" data-value="c" data-label="item-c">
                  Item C
                  </span>
                  <span data-part="item-indicator" data-value="c" data-label="item-c">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="d" data-label="item-d">
                  <span data-part="item-text" data-value="d" data-label="item-d">
                  Item D
                  </span>
                  <span data-part="item-indicator" data-value="d" data-label="item-d">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </ul>
                  </div>
                  </div>

Open your browser's console to see the events received when a listbox item is selected

Data attribute Type / Options Description
data-on-select string Event name to be send when a listbox item is selected
data-on-highlight-change string Event name to be send when a listbox item is highlighted
data-on-value-change string Event name to be send when a listbox value changes

RTL

RTL support for listbox

  • Item A
  • Item B
  • Item C
  • Item D
<div dir="rtl">
                  <div class="listbox listbox-js" data-dir="rtl">
                  <div data-part="root">
                  <label data-part="label">Listbox Label</label>
                  <ul data-part="content">
                  <li data-part="item" data-value="a" data-label="item-a">
                  <span data-part="item-text" data-value="a" data-label="item-a">
                  Item A
                  </span>
                  <span data-part="item-indicator" data-value="a" data-label="item-a">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="b" data-label="item-b">
                  <span data-part="item-text" data-value="b" data-label="item-b">
                  Item B
                  </span>
                  <span data-part="item-indicator" data-value="b" data-label="item-b">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="c" data-label="item-c">
                  <span data-part="item-text" data-value="c" data-label="item-c">
                  Item C
                  </span>
                  <span data-part="item-indicator" data-value="c" data-label="item-c">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="d" data-label="item-d">
                  <span data-part="item-text" data-value="d" data-label="item-d">
                  Item D
                  </span>
                  <span data-part="item-indicator" data-value="d" data-label="item-d">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </ul>
                  </div>
                  </div>
                  </div>

Custom (Tailwind)

If you are using Tailwind styling, you can customize each listbox and its parts with Tailwind utilities

  • Item A
  • Item B
  • Item C
  • Item D
<div class="listbox listbox-js">
                  <div data-part="root" class="bg-red-50 shadow-xl border-2 rounded-xl">
                  <label data-part="label" class="text-blue-600 px-4">Listbox Label</label>
                  <ul data-part="content" class="bg-yellow-50 shadow-xl border-2 rounded-xl">
                  <li data-part="item" data-value="a" data-label="item-a" class="border-2 rounded-xl border-red-300">
                  <span data-part="item-text" data-value="a" data-label="item-a">
                  Item A
                  </span>
                  <span data-part="item-indicator" data-value="a" data-label="item-a" class="border-blue-800">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="b" data-label="item-b" class="border-2 rounded-xl border-red-300">
                  <span data-part="item-text" data-value="b" data-label="item-b">
                  Item B
                  </span>
                  <span data-part="item-indicator" data-value="b" data-label="item-b" class="border-blue-800">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="c" data-label="item-c">
                  <span data-part="item-text" data-value="c" data-label="item-c">
                  Item C
                  </span>
                  <span data-part="item-indicator" data-value="c" data-label="item-c">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  <li data-part="item" data-value="d" data-label="item-d">
                  <span data-part="item-text" data-value="d" data-label="item-d">
                  Item D
                  </span>
                  <span data-part="item-indicator" data-value="d" data-label="item-d">
                  <svg class="item__icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"></path>
                  </svg>
                  </span>
                  </li>
                  </ul>
                  </div>
                  </div>

Templates

Listbox components is available in the followng templates

Link Menu