I tried to use your Combobox code on the site to create it as a generic component, if you think it's interesting we could add it
-->
<script setup lang="ts">
import { defineProps, defineEmits } from "vue";
import { Check, ChevronsUpDown } from "lucide-vue-next";
import { ref, watchEffect } from "vue";
import {
cn,
Button,
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
Popover,
PopoverContent,
PopoverTrigger,
} from "../index";
interface Option {
id: string;
title: string;
}
const props = defineProps<{
options: Option[];
modelValue?: string;
}>();
const emits = defineEmits<{
(e: "update:modelValue", payload: string | number): void;
}>();
// We use an internalModelValue because the Command widget returns the whole `{id: string, title: string}` as value, and we wanted the outer component v-model to only contain the id, for practicality
const internalModelValue = ref<Option | null>(null);
const open = ref(false);
const findItem = (id: string) => props.options.find((t) => t.id === id);
const filterFunction = (list: string[], query: string) => {
return list.filter((i) =>
i.title.toLowerCase().includes(query.toLowerCase())
);
};
watchEffect(() => {
internalModelValue.value = findItem(props.modelValue);
});
</script>
<template>
<Popover v-model:open="open">
<PopoverTrigger as-child>
<Button
variant="outline"
role="combobox"
:aria-expanded="open"
class="w-[200px] justify-between"
>
{{ modelValue ? findItem(modelValue)?.title : "Select..." }}
<ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent class="w-[200px] p-0">
<Command v-model="internalModelValue" :filter-function="filterFunction">
<CommandInput placeholder="Search..." />
<CommandEmpty>No item found.</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="option in options"
:key="option.id"
:value="option"
@select="
($event) => {
open = false;
emits('update:modelValue', option.id);
}
"
>
<Check
:class="
cn(
'mr-2 h-4 w-4',
modelValue === option.id ? 'opacity-100' : 'opacity-0'
)
"
/>
{{ option.title }}
</CommandItem>
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
</template>
(I kept the API such that the "outer v-model" contains only the id, and not the whole element {id: ..., title: ...} so it acts a bit like select / dropdown etc