You need to check for an undefined selected
slot prop. Types are currently bugged.
Usage
Use the compositional components CSelect
& CSelectItem
to compose the select element.
<script lang="ts" setup>
const selectItems = [
{ name: 'Example 1', value: 1, disabled: false },
{ name: 'Example 2', value: 2, disabled: true },
{ name: 'Example 3', value: 3, disabled: false },
]
const selectedVal = ref<number>()
</script>
<template>
<CSelect
v-model="selectedVal"
:options="selectItems"
placeholder="Example select"
by="value"
label="Example select"
class="min-w-50 w-auto"
>
<template #selected="{ selected }">
{{ selected?.name }}
</template>
<template #default="{ items, selected }">
<CSelectItem
v-for="item in items"
:key="item.name"
:selected="item.value === selected?.value"
:value="item.value"
:disabled="item.disabled"
>
{{ item.name }}
</CSelectItem>
</template>
</CSelect>
</template>
Float
The component utilises @headlessui-float/vue
for floating. For the moment only the placement
, offset
and strategy
props are hoisted. The default strategy for the dropdown is absolute
, you can however change this to fixed
as seen below.
<script lang="ts" setup>
const selectItems = ref([
{ name: 'Example 1', value: 1, disabled: false },
{ name: 'Example 2', value: 2, disabled: true },
{ name: 'Example 3', value: 3, disabled: false },
])
const selectedVal = ref()
</script>
<template>
<CSelect
v-model="selectedVal"
:options="selectItems"
placeholder="Example select"
by="value"
display-value="name"
label="Example select"
class="min-w-50 w-auto"
placement="top-start"
strategy="fixed"
>
<template #selected="{ selected }">
{{ selected?.name }}
</template>
<template #default="{ items, selected }">
<CSelectItem
v-for="item in items"
:key="item.name"
:selected="item.value === selected?.value"
:value="item.value"
:disabled="item.disabled"
>
{{ item.name }}
</CSelectItem>
</template>
</CSelect>
</template>
Compositional with empty slot
In some cases you want control over what the empty/placeholer state renders, for example, to mimic an 'Any' option.
<script lang="ts" setup>
const selectItems = [
{ name: 'Example 1', value: 1, disabled: false },
{ name: 'Example 2', value: 2, disabled: true },
{ name: 'Example 3', value: 3, disabled: false },
]
const selectedVal = ref<null | typeof selectItems[number]>(null)
</script>
<template>
<CSelect
v-model="selectedVal"
placeholder="Example select"
label="Example select"
class="min-w-50 w-auto"
>
<template #selected>
{{ selectedVal.name }}
</template>
<!-- This empty slot will render with any falsy model value -->
<template #empty>
Any data center
</template>
<CSelectItem
:selected="selectedVal === null"
:value="null"
>
Any data center
</CSelectItem>
<CSelectItem
v-for="item in selectItems"
:key="item.name"
:selected="item.value === selectedVal?.value"
:value="item"
:disabled="item.disabled"
>
{{ item.name }}
</CSelectItem>
</CSelect>
</template>
Non-compositional
A non-compositional approach can be used with the component, using just props and internal handling to render the child components. The display-value
prop can be used here to select the value you want to use to display.
You need to use display-value
if providing options
with an array of objects for non-compositional use as well as when you need slot values.
<script lang="ts" setup>
const selectItems = ref([
{ name: 'Example 1', value: 1, disabled: false },
{ name: 'Example 2', value: 2, disabled: true },
{ name: 'Example 3', value: 3, disabled: false },
])
const selectedVal = ref()
</script>
<template>
<CSelect
v-model="selectedVal"
:options="selectItems"
placeholder="Example select"
by="value"
display-value="name"
label="Example select"
class="min-w-50 w-auto"
/>
</template>
Active styles
The SelectItem
has a group class that allows us to style based on the parents state. We also apply an .active
class when the item is selected, meaning we can use this with group modifiers to apply custom active styling.
group-[.active]:text-canvas-100
The #default
slot passes through the reactive active
state. You can also use this for custom active styling or logic.
Props
Select
"bottom-start"
"top"
"left"
"bottom"
"right"
"bottom-end"
"top-end"
"top-start"
"left-end"
"left-start"
"bottom-start"
"right-end"
"right-start"
"absolute"
"fixed"
"absolute"
4
number
SelectItem
undefined