<div x-data="{ model: [] }" , class="flex flex-col items-center">
<div
x-data="select"
: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="mr-3 flex flex-1 flex-wrap">
<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>
<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-0 focus:outline-hidden"
readonly
/>
</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>
<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>
<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/select/dist/cdn.min.js"></script>
The data for the component is provided by the select
function in the x-data
directive and the props in the data-*
attributes.
The select 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.
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-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
[]
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.
open-selectmenu
Event dispatched after opening select menu.
scroll-to-bottom
Event dispatched after menu is scrolled to the bottom.
The data-multiple
prop enables the selection of multiple values.
<div x-data="{ model: [] }" , class="flex flex-col items-center">
<div
x-data="select"
: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: 'spanish', value: 'spanish' },
{ text: 'finnish', value: 'finnish' },
{ text: 'thai', value: 'thai' },
]"
data-multiple="true"
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="mr-3 flex flex-1 flex-wrap">
<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>
<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-0 focus:outline-hidden"
readonly
/>
</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>
<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()">
<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>
To load items from a remote resource, simply assign them to the items
property. In the example below, the items are fetched when the select menu is opened.
<div
x-data="{ model: [], isLoading: false }"
class="flex flex-col items-center"
>
<div
x-data="select"
data-item-text="name"
data-item-value="id"
data-use-loader="true"
:data-is-loading="isLoading"
@open-selectmenu="() => {
isLoading = true
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(json => {
items = json
isLoading = false
})
}"
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="mr-3 flex flex-1 flex-wrap">
<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>
<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-0 focus:outline-hidden"
readonly
/>
</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>
<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>
To access any additional fields of the item use the origin
property.
<div
x-data="{ model: [], isLoading: false }"
class="flex flex-col items-center"
>
<div
x-data="select"
data-item-text="name"
data-item-value="id"
data-use-loader="true"
:data-is-loading="isLoading"
@open-selectmenu="() => {
isLoading = true
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(json => {
items = json
isLoading = false
})
}"
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="mr-3 flex flex-1 flex-wrap">
<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>
<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-0 focus:outline-hidden"
readonly
/>
</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>
<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"
>
<div class="flex flex-col">
<span x-text="item.text"></span>
<span
x-text="item.origin.company.name"
class="text-sm text-text-500 dark:text-text-400"
></span>
<span
x-text="item.origin.address.city"
class="text-xs text-text-500 dark:text-text-400"
></span>
</div>
</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>