Skip to content

Combobox

A combobox is an input field that allows users to select one or more items from a list of options.

---
---
<script is:inline>
window.FRUITS = [
"Apple",
"Apricot",
"Banana",
"Blackberry",
"Blueberry",
"Cherry",
"Cranberry",
"Grape",
"Kiwi",
"Lemon",
"Lime",
"Mango",
"Orange",
"Papaya",
"Peach",
"Pear",
"Pineapple",
"Plum",
"Raspberry",
"Strawberry",
"Watermelon"
]
</script>
<div
x-cloak
x-data="{ options: { value: [...FRUITS] } }"
x-combobox={`
{
items: options,
itemToValue: (it) => it,
itemToString: (it) => it,
inputBehavior: "autohighlight",
placeholder: 'Type or select a fruit',
positioning: { flip: true, sameWidth: true }
}
`}
x-on:z-open-change="options.value = [...FRUITS]"
x-on:z-input-value-change={`
const input = $event.detail.inputValue
const filtered = FRUITS.filter((it) => it.toLowerCase().includes(input.toLowerCase()))
options.value = filtered.length > 0 ? filtered : [...FRUITS]
`}
>
<label x-combobox:label>Pick your favorite fruit</label>
<div x-combobox:control>
<input x-combobox:input />
<button x-combobox:trigger type="button">
<i class="i-lucide-chevrons-up-down w-4 h-4"></i>
</button>
</div>
<template x-teleport="body">
<div x-combobox:positioner>
<div x-combobox:content>
<ul>
<template x-for="item in options.value" :key="item">
<li>
<button type="button" x-combobox:item="{ item }" x-text="item"></button>
</li>
</template>
</ul>
</div>
</div>
</template>
</div>
<style>
[data-part="root"] {
@apply flex flex-col gap-1;
}
[data-part="label"] {
@apply font-medium;
}
[data-part="control"] {
@apply relative;
}
[data-part="input"] {
@apply px-2.5 h-9 min-w-48 bg-white text-zinc-700 border border-zinc-300/60 rounded outline-none focus:outline-zinc-500;
}
[data-part="trigger"] {
@apply absolute inset-y-0 right-2 inline-flex items-center justify-center text-zinc-700 bg-transparent cursor-pointer;
}
[data-part="content"] {
@apply relative z-[1400] max-h-48 bg-white border border-zinc-200/60 p-1 rounded-md shadow-md overflow-auto;
}
[data-part="content"] > ul {
@apply flex flex-col p-0;
}
[data-part="content"] > ul > li {
@apply list-none;
}
[data-part="item"] {
@apply w-full text-sm text-left font-medium text-zinc-700 bg-transparent cursor-pointer px-2 py-1 rounded;
}
[data-part="item"][data-highlighted] {
@apply bg-zinc-100;
}
@keyframes enter {
from {
opacity: 0;
transform: scale(0.95) translateY(-10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
@keyframes exit {
from {
opacity: 1;
transform: scale(1) translateY(0);
}
to {
opacity: 0;
transform: scale(0.95) translateY(-10px);
}
}
[data-part="content"][data-state="open"] {
animation: enter 0.2s ease-out;
}
[data-part="content"][data-state="closed"] {
animation: exit 0.2s ease-out;
}
</style>