Searchable select with async loading support
Tags: component form selection
Combobox is a searchable dropdown that supports filtering options and async data loading.
Import
<script>
import { Combobox } from '@classic-homes/theme-svelte';
</script>Basic Usage
<script>
let value = $state('');
const options = [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'orange', label: 'Orange' },
];
</script>
<Combobox {options} bind:value placeholder="Select a fruit..." />Props
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string |
'' |
Current selected value (bindable) |
options |
(ComboboxOption | SelectGroup)[] |
Required | Array of options or grouped options |
placeholder |
string |
'Select an option...' |
Placeholder text |
emptyMessage |
string |
'No results found.' |
Message when no options match |
disabled |
boolean |
false |
Disables the combobox |
required |
boolean |
false |
Marks as required |
name |
string |
- | Name attribute for forms |
id |
string |
- | Element ID (auto-generated if empty) |
label |
string |
- | Label text |
hint |
string |
- | Hint text below the input |
error |
string |
- | Error message |
loading |
boolean |
false |
Shows loading state |
debounceMs |
number |
300 |
Debounce time for search |
onValueChange |
(value: string) => void |
- | Callback when value changes |
onSearch |
(query: string) => void |
- | Callback for search queries |
class |
string |
- | Additional CSS classes |
With Label and Hint
<Combobox label="Select Country" hint="Start typing to search" options={countries} bind:value />Searchable
Users can type to filter options:
<Combobox options={countries} bind:value placeholder="Search countries..." />Closed, the input shows the selected option's label. Opened, it clears so the full list shows, with the selected label as the placeholder.
Grouped Options
Pass SelectGroups, the same shape Select takes. Typing filters within each group and hides groups with no match.
<Combobox
label="Plan"
options={[
{ label: 'Ranch', options: [{ value: 'aspen', label: 'Aspen' }] },
{ label: 'Two-story', options: [{ value: 'birch', label: 'Birch' }] },
]}
bind:value
/>Async Loading
Load options based on search query:
<script>
let value = $state('');
let options = $state([]);
let loading = $state(false);
async function handleSearch(query: string) {
loading = true;
try {
const response = await fetch(`/api/search?q=${query}`);
options = await response.json();
} finally {
loading = false;
}
}
</script>
<Combobox
label="Search"
{options}
bind:value
{loading}
onSearch={handleSearch}
placeholder="Search..."
emptyMessage="Type to search..."
/>With Debounce
Control the debounce timing:
<Combobox {options} bind:value onSearch={handleSearch} debounceMs={500} />Validation
Show validation errors:
<Combobox
label="Country"
{options}
bind:value
required
error={!value ? 'Please select an option' : ''}
/>Accessibility
The Combobox component includes:
- Full keyboard navigation
- ARIA combobox pattern
- Screen reader announcements
- Focus management
- Auto-generated IDs link labels to inputs
aria-describedbyconnects hint and error messagesaria-invalidset when error is present
Examples
User Search
<script>
let selectedUser = $state('');
let users = $state([]);
let loading = $state(false);
async function searchUsers(query: string) {
if (!query) {
users = [];
return;
}
loading = true;
const response = await fetch(`/api/users?search=${query}`);
users = await response.json();
loading = false;
}
</script>
<Combobox
label="User"
options={users}
bind:value={selectedUser}
onSearch={searchUsers}
{loading}
placeholder="Search users..."
emptyMessage="No users found"
/>Location Autocomplete
<Combobox
label="Location"
hint="Enter a city name or zip code"
options={locations}
bind:value
onSearch={searchLocations}
placeholder="Enter city or zip code..."
emptyMessage="No locations found"
/>Related Components
- Select - Simple dropdown without search
- MultiSelect - Select multiple options