Select

Display a select element.

Usage

Use the compositional components CSelect & CSelectItem to compose the select element.

<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"
    label="Example select"
    class="min-w-50 w-auto"
  >
    <template #selected="{ selected }">
      {{ selected.name }}
    </template>
    <template #default="{ items }">
      <CSelectItem
        v-for="item in items"
        :key="item.name"
        :selected="item.value === selectedVal"
        :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 }">
      <CSelectItem
        v-for="item in items"
        :key="item.name"
        :selected="item.value === selectedVal"
        :value="item.value"
        :disabled="item.disabled"
      >
        {{ item.name }}
      </CSelectItem>
    </template>
  </CSelect>
</template>

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 = 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 #selected="{ selected }">
      {{ selected.name }}
    </template>
    <template #empty>
      Any data center
    </template>
    <template #default="{ items }">
      <CSelectItem
        :selected="selectedVal === undefined"
        :value="undefined"
      >
        Any data center
      </CSelectItem>
      <CSelectItem
        v-for="item in items"
        :key="item.name"
        :selected="item.value === selectedVal"
        :value="item.value"
        :disabled="item.disabled"
      >
        {{ item.name }}
      </CSelectItem>
    </template>
  </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.

For best practice, use display-value where possible (if using an array of objects), even if creating a Select dropdown compositionally. The selected value is used internally to display the title attribute.

<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

modelValuerequired
any
placement
Placement
"bottom-start"
"top""left""bottom""right""bottom-end""top-end""top-start""left-end""left-start""bottom-start""right-end""right-start"
strategy
Strategy
"absolute"
"fixed""absolute"
offset
number
4
name
string
placeholder
string
label
string
id
string
errors
string[]
by
string
options
string[] | { [key: string]: any; disabled?: boolean; }[]
displayValue
string
loading
boolean
required
boolean
disabled
boolean

SelectItem

selectedrequired
boolean
value
string | number | boolean | object
undefined
icon
string
tags
any[]
disabled
boolean