Autocomplete

Example
x-model:

<div x-data="{ model: [] }" , class="flex flex-col items-center">
  <div
    x-data="autocomplete"
    :data-items="[
      { text: 'spanish', value: 'spanish' },
      { text: 'french', value: 'french' },
      { text: 'portuguese', value: 'portuguese' },
      { text: 'german', value: 'german' },
      { text: 'japanese', value: 'japanese' },
      { text: 'korean', value: 'korean' },
      { text: 'italian', value: 'italian' },
      { text: 'polish', value: 'polish' },
      { text: 'greek', value: 'greek'},
      { text: 'swedish', value: 'swedish' },
      { text: 'norwegian', value: 'norwegian' },
      { text: 'danish', value: 'danish' },
      { text: 'finnish', value: 'finnish' },
      { text: 'thai', value: 'thai' },
    ]"
    x-model="model"
    class="w-[340px]"
  >
    <div
      x-bind="trigger"
      x-data="input"
      class="flex flex-1 items-center rounded-sm border px-3 py-2 outline-hidden transition-shadow duration-200 focus-within:ring-3 focus:outline-hidden"
      class-default="border-gray-300 bg-white focus-within:border-gray-400 focus-within:ring-primary-200 dark:border-dark-600 dark:bg-dark-800 dark:text-text-300 dark:focus-within:ring-primary-300"
      class-valid="border-success-300 bg-white text-success-600 focus-within:ring-success-200 dark:border-success-400 dark:bg-dark-800 dark:text-success-600 dark:focus-within:ring-success-300"
      class-invalid="border-danger-300 bg-white text-danger-600 focus-within:ring-danger-200 dark:border-danger-400 dark:bg-dark-800 dark:text-danger-600 dark:focus-within:ring-danger-300"
    >
      <div data-icon class="mr-3 empty:hidden"></div>
      <div data-prepend class="mr-3 empty:hidden"></div>
      <div class="relative mr-3 flex flex-1 flex-wrap overflow-hidden">
        <div x-bind="selectedItems">
          <template x-for="selectedItem in getSelected()">
            <span
              x-text="selectedItem.text"
              class="mr-1 after:content-[','] last-of-type:mr-2 last-of-type:after:content-none"
            ></span>
          </template>
        </div>
        <input
          x-bind="input"
          type="text"
          class="w-full min-w-0 flex-1 border-0 bg-transparent p-0 outline-hidden focus:min-w-[64px] focus:outline-hidden"
        />
      </div>
      <div data-append class="mr-3 empty:hidden"></div>
      <div class="flex items-center gap-x-2">
        <div x-bind="loader">
          <svg
            viewBox="25 25 50 50"
            fill="none"
            class="h-5 w-5 animate-spinner-rotate"
          >
            <circle
              cx="50"
              cy="50"
              r="20"
              stroke="currentColor"
              stroke-width="4"
              stroke-miterlimit="10"
              stroke-linecap="round"
              class="animate-spinner-dash"
            />
          </svg>
        </div>
        <button
          x-bind="clearButton"
          @click="clearSelection()"
          class="flex items-center"
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="16"
            height="16"
            fill="currentColor"
            class="pointer-events-none h-5 w-5 opacity-70"
            viewBox="0 0 16 16"
          >
            <path
              d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"
            />
          </svg>
        </button>
        <button x-bind="indicator">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="currentColor"
            viewBox="0 0 512 512"
            class="h-4 w-4 rotate-180 transform duration-200"
            :class="{ 'rotate-0!': isOpen }"
          >
            <path
              d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"
            />
          </svg>
        </button>
      </div>
    </div>
    <div
      x-bind="menu"
      class="oveflow-y-auto z-50 max-h-[400px] overflow-x-hidden rounded-b-md bg-white shadow-md dark:bg-dark-800"
      x-alt-transition='{
        "enter": ["opacity-0 scale-y-[0.5]", "transition ease-out duration-100 origin-top", "opacity-100"],
        "leave": ["opacity-100", "transition ease-in duration-100 origin-top", "opacity-0 scale-y-[0.5]"]
      }'
    >
      <template x-if="getItems().length === 0">
        <div class="px-6 py-4 text-left text-text-800 dark:text-text-300">
          No items available.
        </div>
      </template>
      <template x-for="(item, index) in getItems()" :key="item.value">
        <button
          x-bind="option"
          class="w-full cursor-pointer scroll-mt-20 scroll-mb-20 px-6 py-4 text-left ring-secondary-400 transition-colors ring-inset focus:ring-2 focus:outline-hidden"
          class-default="text-text-800 hover:bg-secondary-100 focus:bg-secondary-200 dark:text-text-300 dark:hover:bg-dark-600 dark:focus:bg-dark-600"
          class-selected="bg-secondary-200 focus:bg-secondary-300 dark:bg-dark-600 dark:focus:bg-dark-700"
        >
          <span x-text="item.text"></span>
        </button>
      </template>
    </div>
  </div>
  <div class="mx-auto mt-4 w-max font-mono text-lg">
    x-model: <span x-text="JSON.stringify(model)"></span>
  </div>
</div>

Usage

<script defer src="https://cdn.jsdelivr.net/npm/litewind-alpine@0.x.x/plugins/use-floating/dist/cdn.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/litewind-alpine@0.x.x/components/autocomplete/dist/cdn.min.js"></script>

The data for the component is provided by the autocomplete function in the x-data directive and the props in the data-* attributes.

The autocomplete component is based on the input component, so you can use any of its props or additional elements such as a clear button, icon, loader, and more. See the documentation for the input component here.

Props

data-items
[] Array

Array of items to select. This can be an array of strings or an array of objects. The objects should have at least two properties: a text that will be displayed in the menu and a value. This prop is optional, items can be assigned directly to the items property.


data-item-text
text String

Name of the property that holds the displayed text of the item.


data-item-value
value String

Name of the property that holds the value of the item.


data-multiple
false Boolean

Allows selecting multiple values.


data-no-filter
false Boolean

Disables internal filtering. This is useful when data is filtered on the server.


data-no-empty-open
false Boolean

Prevents the select menu from opening when the items array is empty. Useful for autocomplete components that filter data on the server side.


data-clearable
false Boolean

Adds an X button that resets model to the default value.


data-use-loader
false Boolean

Enable or disable the spinner in the input.


data-is-loading
false Boolean

If true displays a spinner in the input. Spinner should be first enabled in the data-use-loader prop.


data-placeholder
empty string String

Sets the placeholder of the input element.

x-model

x-model
[] Array

The type of the x-model is an array for single and multiple modes. The values in the array are the value fields of the selected options.

Events

open-selectmenu

Event dispatched after opening select menu.


scroll-to-bottom

Event dispatched after menu is scrolled to the bottom.

Multiple values

The data-multiple prop enables the selection of multiple values.

Example
x-model:

<div x-data="{ model: [] }" , class="flex flex-col items-center">
  <div
    x-data="autocomplete"
    :data-items="[
      { text: 'spanish', value: 'spanish' },
      { text: 'french', value: 'french' },
      { text: 'portuguese', value: 'portuguese' },
      { text: 'german', value: 'german' },
      { text: 'japanese', value: 'japanese' },
      { text: 'korean', value: 'korean' },
      { text: 'italian', value: 'italian' },
      { text: 'polish', value: 'polish' },
      { text: 'greek', value: 'greek'},
      { text: 'swedish', value: 'swedish' },
      { text: 'norwegian', value: 'norwegian' },
      { text: 'danish', value: 'danish' },
      { text: 'finnish', value: 'finnish' },
      { text: 'thai', value: 'thai' },
    ]"
    data-multiple
    x-model="model"
    class="w-[340px]"
  >
    <div
      x-bind="trigger"
      x-data="input"
      class="flex flex-1 items-center rounded-sm border px-3 py-2 outline-hidden transition-shadow duration-200 focus-within:ring-3 focus:outline-hidden"
      class-default="border-gray-300 bg-white focus-within:border-gray-400 focus-within:ring-primary-200 dark:border-dark-600 dark:bg-dark-800 dark:text-text-300 dark:focus-within:ring-primary-300"
      class-valid="border-success-300 bg-white text-success-600 focus-within:ring-success-200 dark:border-success-400 dark:bg-dark-800 dark:text-success-600 dark:focus-within:ring-success-300"
      class-invalid="border-danger-300 bg-white text-danger-600 focus-within:ring-danger-200 dark:border-danger-400 dark:bg-dark-800 dark:text-danger-600 dark:focus-within:ring-danger-300"
    >
      <div data-icon class="mr-3 empty:hidden"></div>
      <div data-prepend class="mr-3 empty:hidden"></div>
      <div class="relative mr-3 flex flex-1 flex-wrap overflow-hidden">
        <div x-bind="selectedItems">
          <template x-for="selectedItem in getSelected()">
            <span
              x-text="selectedItem.text"
              class="mr-1 after:content-[','] last-of-type:mr-2 last-of-type:after:content-none"
            ></span>
          </template>
        </div>
        <input
          x-bind="input"
          type="text"
          class="w-full min-w-0 flex-1 border-0 bg-transparent p-0 outline-hidden focus:min-w-[64px] focus:outline-hidden"
        />
      </div>
      <div data-append class="mr-3 empty:hidden"></div>
      <div class="flex items-center gap-x-2">
        <div x-bind="loader">
          <svg
            viewBox="25 25 50 50"
            fill="none"
            class="h-5 w-5 animate-spinner-rotate"
          >
            <circle
              cx="50"
              cy="50"
              r="20"
              stroke="currentColor"
              stroke-width="4"
              stroke-miterlimit="10"
              stroke-linecap="round"
              class="animate-spinner-dash"
            />
          </svg>
        </div>
        <button
          x-bind="clearButton"
          @click="clearSelection()"
          class="flex items-center"
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="16"
            height="16"
            fill="currentColor"
            class="pointer-events-none h-5 w-5 opacity-70"
            viewBox="0 0 16 16"
          >
            <path
              d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"
            />
          </svg>
        </button>
        <button x-bind="indicator">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="currentColor"
            viewBox="0 0 512 512"
            class="h-4 w-4 rotate-180 transform duration-200"
            :class="{ 'rotate-0!': isOpen }"
          >
            <path
              d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"
            />
          </svg>
        </button>
      </div>
    </div>
    <div
      x-bind="menu"
      class="oveflow-y-auto z-50 max-h-[400px] overflow-x-hidden rounded-b-md bg-white shadow-md dark:bg-dark-800"
      x-alt-transition='{
        "enter": ["opacity-0 scale-y-[0.5]", "transition ease-out duration-100 origin-top", "opacity-100"],
        "leave": ["opacity-100", "transition ease-in duration-100 origin-top", "opacity-0 scale-y-[0.5]"]
      }'
    >
      <template x-if="getItems().length === 0">
        <div class="px-6 py-4 text-left text-text-800 dark:text-text-300">
          No items available.
        </div>
      </template>
      <template x-for="(item, index) in getItems()" :key="item.value">
        <button
          x-bind="option"
          class="w-full cursor-pointer scroll-mt-20 scroll-mb-20 px-6 py-4 text-left ring-secondary-400 transition-colors ring-inset focus:ring-2 focus:outline-hidden"
          class-default="text-text-800 hover:bg-secondary-100 focus:bg-secondary-200 dark:text-text-300 dark:hover:bg-dark-600 dark:focus:bg-dark-600"
          class-selected="bg-secondary-200 focus:bg-secondary-300 dark:bg-dark-600 dark:focus:bg-dark-700"
        >
          <span x-text="item.text"></span>
        </button>
      </template>
    </div>
  </div>
  <div class="mx-auto mt-4 w-max font-mono text-lg">
    x-model: <span x-text="JSON.stringify(model)"></span>
  </div>
</div>

Autocomplete async

The data-no-filter disables internal filtering. This can be useful when data is filtered on the server side. In the example below, the server response replaces the items array with the filtered results after each query. The data-no-empty-open prop prevents opening the menu when the items array is empty.

Example
x-model:

<div
  x-data="{ 
    model: [],
    isLoading: false,
    filteredItems: [],
    async query(q) {
      if (q === '') {
        this.filteredItems = []
        return
      }
      this.isLoading = true
      let res = await fetch(`https://en.wikipedia.org/w/api.php?action=query&format=json&list=prefixsearch&formatversion=2&origin=*&pslimit=50&pssearch=${q}`)
      let data = await res.json()
      this.filteredItems = data.query.prefixsearch
      this.isLoading = false
    },
  }"
  @update:value.debounce="query($event.detail)"
  class="flex flex-col items-center"
>
  <div
    x-data="autocomplete"
    :data-items="filteredItems"
    data-no-filter
    data-item-text="title"
    data-item-value="pageid"
    data-use-loader
    :data-is-loading="isLoading"
    data-no-empty-open
    x-model="model"
    class="w-[340px]"
  >
    <div
      x-bind="trigger"
      x-data="input"
      class="flex flex-1 items-center rounded-sm border px-3 py-2 outline-hidden transition-shadow duration-200 focus-within:ring-3 focus:outline-hidden"
      class-default="border-gray-300 bg-white focus-within:border-gray-400 focus-within:ring-primary-200 dark:border-dark-600 dark:bg-dark-800 dark:text-text-300 dark:focus-within:ring-primary-300"
      class-valid="border-success-300 bg-white text-success-600 focus-within:ring-success-200 dark:border-success-400 dark:bg-dark-800 dark:text-success-600 dark:focus-within:ring-success-300"
      class-invalid="border-danger-300 bg-white text-danger-600 focus-within:ring-danger-200 dark:border-danger-400 dark:bg-dark-800 dark:text-danger-600 dark:focus-within:ring-danger-300"
    >
      <div data-icon class="mr-3 empty:hidden"></div>
      <div data-prepend class="mr-3 empty:hidden"></div>
      <div class="relative mr-3 flex flex-1 flex-wrap overflow-hidden">
        <div x-bind="selectedItems">
          <template x-for="selectedItem in getSelected()">
            <span
              x-text="selectedItem.text"
              class="mr-1 after:content-[','] last-of-type:mr-2 last-of-type:after:content-none"
            ></span>
          </template>
        </div>
        <input
          x-bind="input"
          type="text"
          class="w-full min-w-0 flex-1 border-0 bg-transparent p-0 outline-hidden focus:min-w-[64px] focus:outline-hidden"
        />
      </div>
      <div data-append class="mr-3 empty:hidden"></div>
      <div class="flex items-center gap-x-2">
        <div x-bind="loader">
          <svg
            viewBox="25 25 50 50"
            fill="none"
            class="h-5 w-5 animate-spinner-rotate"
          >
            <circle
              cx="50"
              cy="50"
              r="20"
              stroke="currentColor"
              stroke-width="4"
              stroke-miterlimit="10"
              stroke-linecap="round"
              class="animate-spinner-dash"
            />
          </svg>
        </div>
        <button
          x-bind="clearButton"
          @click="clearSelection()"
          class="flex items-center"
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="16"
            height="16"
            fill="currentColor"
            class="pointer-events-none h-5 w-5 opacity-70"
            viewBox="0 0 16 16"
          >
            <path
              d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"
            />
          </svg>
        </button>
        <button x-bind="indicator">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="currentColor"
            viewBox="0 0 512 512"
            class="h-4 w-4 rotate-180 transform duration-200"
            :class="{ 'rotate-0!': isOpen }"
          >
            <path
              d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"
            />
          </svg>
        </button>
      </div>
    </div>
    <div
      x-bind="menu"
      class="oveflow-y-auto z-50 max-h-[400px] overflow-x-hidden rounded-b-md bg-white shadow-md dark:bg-dark-800"
      x-alt-transition='{
        "enter": ["opacity-0 scale-y-[0.5]", "transition ease-out duration-100 origin-top", "opacity-100"],
        "leave": ["opacity-100", "transition ease-in duration-100 origin-top", "opacity-0 scale-y-[0.5]"]
      }'
    >
      <template x-if="getItems().length === 0">
        <div class="px-6 py-4 text-left text-text-800 dark:text-text-300">
          No items available.
        </div>
      </template>
      <template x-for="(item, index) in getItems()" :key="item.value">
        <button
          x-bind="option"
          class="w-full cursor-pointer scroll-mt-20 scroll-mb-20 px-6 py-4 text-left ring-secondary-400 transition-colors ring-inset focus:ring-2 focus:outline-hidden"
          class-default="text-text-800 hover:bg-secondary-100 focus:bg-secondary-200 dark:text-text-300 dark:hover:bg-dark-600 dark:focus:bg-dark-600"
          class-selected="bg-secondary-200 focus:bg-secondary-300 dark:bg-dark-600 dark:focus:bg-dark-700"
        >
          <span x-text="item.text"></span>
        </button>
      </template>
    </div>
  </div>
  <div class="mx-auto mt-4 w-max font-mono text-lg">
    x-model: <span x-text="JSON.stringify(model)"></span>
  </div>
</div>

Option highlight

By default, the filtered portion of the option text is not highlighted as it requires x-html directive. You can enable it by simply replacing x-text with x-html in the span element of the option.

<span x-html="getHighlightedItemText"></span>
Example
x-model:

<div x-data="{ model: [] }" , class="flex flex-col items-center">
  <div
    x-data="autocomplete"
    :data-items="[
      { text: 'spanish', value: 'spanish' },
      { text: 'french', value: 'french' },
      { text: 'portuguese', value: 'portuguese' },
      { text: 'german', value: 'german' },
      { text: 'japanese', value: 'japanese' },
      { text: 'korean', value: 'korean' },
      { text: 'italian', value: 'italian' },
      { text: 'polish', value: 'polish' },
      { text: 'greek', value: 'greek'},
      { text: 'swedish', value: 'swedish' },
      { text: 'norwegian', value: 'norwegian' },
      { text: 'danish', value: 'danish' },
      { text: 'finnish', value: 'finnish' },
      { text: 'thai', value: 'thai' },
    ]"
    x-model="model"
    class="w-[340px]"
  >
    <div
      x-bind="trigger"
      x-data="input"
      class="flex flex-1 items-center rounded-sm border px-3 py-2 outline-hidden transition-shadow duration-200 focus-within:ring-3 focus:outline-hidden"
      class-default="border-gray-300 bg-white focus-within:border-gray-400 focus-within:ring-primary-200 dark:border-dark-600 dark:bg-dark-800 dark:text-text-300 dark:focus-within:ring-primary-300"
      class-valid="border-success-300 bg-white text-success-600 focus-within:ring-success-200 dark:border-success-400 dark:bg-dark-800 dark:text-success-600 dark:focus-within:ring-success-300"
      class-invalid="border-danger-300 bg-white text-danger-600 focus-within:ring-danger-200 dark:border-danger-400 dark:bg-dark-800 dark:text-danger-600 dark:focus-within:ring-danger-300"
    >
      <div data-icon class="mr-3 empty:hidden"></div>
      <div data-prepend class="mr-3 empty:hidden"></div>
      <div class="relative mr-3 flex flex-1 flex-wrap overflow-hidden">
        <div x-bind="selectedItems">
          <template x-for="selectedItem in getSelected()">
            <span
              x-text="selectedItem.text"
              class="mr-1 after:content-[','] last-of-type:mr-2 last-of-type:after:content-none"
            ></span>
          </template>
        </div>
        <input
          x-bind="input"
          type="text"
          class="w-full min-w-0 flex-1 border-0 bg-transparent p-0 outline-hidden focus:min-w-[64px] focus:outline-hidden"
        />
      </div>
      <div data-append class="mr-3 empty:hidden"></div>
      <div class="flex items-center gap-x-2">
        <div x-bind="loader">
          <svg
            viewBox="25 25 50 50"
            fill="none"
            class="h-5 w-5 animate-spinner-rotate"
          >
            <circle
              cx="50"
              cy="50"
              r="20"
              stroke="currentColor"
              stroke-width="4"
              stroke-miterlimit="10"
              stroke-linecap="round"
              class="animate-spinner-dash"
            />
          </svg>
        </div>
        <button
          x-bind="clearButton"
          @click="clearSelection()"
          class="flex items-center"
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="16"
            height="16"
            fill="currentColor"
            class="pointer-events-none h-5 w-5 opacity-70"
            viewBox="0 0 16 16"
          >
            <path
              d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"
            />
          </svg>
        </button>
        <button x-bind="indicator">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="currentColor"
            viewBox="0 0 512 512"
            class="h-4 w-4 rotate-180 transform duration-200"
            :class="{ 'rotate-0!': isOpen }"
          >
            <path
              d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"
            />
          </svg>
        </button>
      </div>
    </div>
    <div
      x-bind="menu"
      class="oveflow-y-auto z-50 max-h-[400px] overflow-x-hidden rounded-b-md bg-white shadow-md dark:bg-dark-800"
      x-alt-transition='{
        "enter": ["opacity-0 scale-y-[0.5]", "transition ease-out duration-100 origin-top", "opacity-100"],
        "leave": ["opacity-100", "transition ease-in duration-100 origin-top", "opacity-0 scale-y-[0.5]"]
      }'
    >
      <template x-if="getItems().length === 0">
        <div class="px-6 py-4 text-left text-text-800 dark:text-text-300">
          No items available.
        </div>
      </template>
      <template x-for="(item, index) in getItems()" :key="item.value">
        <button
          x-bind="option"
          class="w-full cursor-pointer scroll-mt-20 scroll-mb-20 px-6 py-4 text-left ring-secondary-400 transition-colors ring-inset focus:ring-2 focus:outline-hidden"
          class-default="text-text-800 hover:bg-secondary-100 focus:bg-secondary-200 dark:text-text-300 dark:hover:bg-dark-600 dark:focus:bg-dark-600"
          class-selected="bg-secondary-200 focus:bg-secondary-300 dark:bg-dark-600 dark:focus:bg-dark-700"
        >
          <span x-html="getHighlightedItemText"></span>
        </button>
      </template>
    </div>
  </div>
  <div class="mx-auto mt-4 w-max font-mono text-lg">
    x-model: <span x-text="JSON.stringify(model)"></span>
  </div>
</div>
Litewind-alpine 0.1.0