Skip to content

Select

Native dropdown with custom chevron, matching Input.vue dimensions and focus styles. Accepts string or object option arrays.

Examples

Basic

Tailwind v4
vue
<script setup>
import { ref } from 'vue'
const product = ref('')
</script>

<template>
  <Select
    v-model="product"
    placeholder="Choose a product"
    :options="['Crusher Run', 'Screenings', 'Gabion Stone', 'Rip Rap']"
  />
</template>

Object options

Tailwind v4
vue
<Select
  v-model="status"
  :options="[
    { label: 'Active', value: 'active' },
    { label: 'Inactive', value: 'inactive' },
    { label: 'Archived', value: 'archived' },
  ]"
/>

With hint and error

Tailwind v4
vue
<Select
  v-model="shift"
  :options="['Morning', 'Afternoon', 'Night']"
  hint="Shifts start at 6 AM, 2 PM, and 10 PM"
/>
<Select
  v-model="section"
  :options="['A', 'B', 'C']"
  error="Please select a section"
/>

Disabled

Tailwind v4
vue
<Select :model-value="'Screenings'" :options="['Crusher Run', 'Screenings']" disabled />

Searchable (client-side filter)

Set searchable to render a text input inside the open dropdown. By default it filters the existing options array client-side with a case-insensitive substring match — no extra wiring required.

Tailwind v4
vue
<script setup>
import { ref } from 'vue'
const product = ref('')
</script>

<template>
  <Select
    v-model="product"
    searchable
    placeholder="Search products"
    :options="['Crusher Run', 'Screenings', 'Gabion Stone', 'Rip Rap']"
  />
</template>

Searchable + async (onSearch)

Pass onSearch to run your own server-side/async filtering instead of (or in addition to) the built-in client-side filter. Combine with loading so the dropdown shows a loading indicator and skips client-side filtering while you're fetching — update the options prop reactively from the parent once results arrive.

Tailwind v4
vue
<script setup>
import { ref } from 'vue'

const product = ref('')
const options = ref([
  { label: 'Crusher Run', value: 'crusher' },
  { label: 'Screenings', value: 'screenings' },
])
const loading = ref(false)

async function handleSearch(query) {
  loading.value = true
  const results = await fetchProducts(query) // your API call
  options.value = results
  loading.value = false
}
</script>

<template>
  <Select
    v-model="product"
    searchable
    :loading="loading"
    :on-search="handleSearch"
    :options="options"
    placeholder="Search products (async)"
  />
</template>

Props

PropTypeDefaultDescription
modelValuestring | numberCurrently selected value
optionsArray<{ label: string; value: string | number } | string>Option list; strings are used as both label and value
placeholderstringPlaceholder option shown when no value is selected
disabledbooleanfalsePrevents interaction and dims the control
errorstringValidation error message shown below the select
hintstringHelper text shown below the select when no error
searchablebooleanfalseRenders a search input inside the open dropdown and enables client-side filtering
onSearch(query: string) => void | Promise<any>Debounced (~250ms) callback fired as the user types; use for async/server-side filtering
loadingbooleanfalseShows a loading indicator in the dropdown and disables client-side filtering
noResultsTextstring'No results found'Text shown when the filtered option list is empty

Emits

EventPayloadDescription
update:modelValuestring | numberNew value on change

Private — Jetpack Labs internal use only