Select
Native dropdown with custom chevron, matching Input.vue dimensions and focus styles. Accepts string or object option arrays.
Examples
Basic
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
vue
<Select
v-model="status"
:options="[
{ label: 'Active', value: 'active' },
{ label: 'Inactive', value: 'inactive' },
{ label: 'Archived', value: 'archived' },
]"
/>With hint and error
Shifts start at 6 AM, 2 PM, and 10 PM
Please select a section
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
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.
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.
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
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | string | number | — | Currently selected value |
options | Array<{ label: string; value: string | number } | string> | — | Option list; strings are used as both label and value |
placeholder | string | — | Placeholder option shown when no value is selected |
disabled | boolean | false | Prevents interaction and dims the control |
error | string | — | Validation error message shown below the select |
hint | string | — | Helper text shown below the select when no error |
searchable | boolean | false | Renders 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 |
loading | boolean | false | Shows a loading indicator in the dropdown and disables client-side filtering |
noResultsText | string | 'No results found' | Text shown when the filtered option list is empty |
Emits
| Event | Payload | Description |
|---|---|---|
update:modelValue | string | number | New value on change |