Select
Import
Section titled “Import”import { Select } from '@delightstack/components';The SelectOption type is also available:
import type { SelectOption } from '@delightstack/components';Basic Usage
Section titled “Basic Usage” United States
Canada
United Kingdom
Germany
View code
<script> import { Select } from '@delightstack/components';
let country = $state('');
const countries = [ { value: 'us', label: 'United States' }, { value: 'ca', label: 'Canada' }, { value: 'uk', label: 'United Kingdom' }, { value: 'de', label: 'Germany' }, ];</script>
<Select bind:value={country} options={countries} label="Country" placeholder="Select a country" />Examples
Section titled “Examples”Simple Select
Section titled “Simple Select”Select a country
United States
Canada
United Kingdom
Germany
View code
<Select options={[ { value: 'us', label: 'United States' }, { value: 'ca', label: 'Canada' }, { value: 'uk', label: 'United Kingdom' }, { value: 'de', label: 'Germany' }, ]} label="Country" placeholder="Select a country"/>Searchable
Section titled “Searchable”Enable searchable to add a filter input in the dropdown.
Search countries...
United States
Canada
United Kingdom
Australia
Germany
France
Japan
Brazil
View code
<Select searchable bind:value={country} options={countries} label="Country"/>Multi-Select with Chips
Section titled “Multi-Select with Chips”Selected values appear as chips in the trigger. Each chip has a remove button.
Select tags...
Featured
New
On Sale
Popular
Limited Edition
View code
<script> import { Select } from '@delightstack/components';
let selectedTags = $state<string[]>([]);
const tags = [ { value: 'featured', label: 'Featured' }, { value: 'new', label: 'New' }, { value: 'sale', label: 'On Sale' }, ];</script>
<Select multiple bind:value={selectedTags} options={tags} label="Tags" clearable />Option Groups
Section titled “Option Groups”Options with a group property are visually grouped under section headers.
Select a food...
Fruits
Apple
Banana
Cherry
Vegetables
Carrot
Broccoli
Spinach
View code
<script> import { Select } from '@delightstack/components';
const options = [ { value: 'apple', label: 'Apple', group: 'Fruits' }, { value: 'banana', label: 'Banana', group: 'Fruits' }, { value: 'carrot', label: 'Carrot', group: 'Vegetables' }, { value: 'broccoli', label: 'Broccoli', group: 'Vegetables' }, ];</script>
<Select bind:value={selected} options={options} label="Food" />Async Loading
Section titled “Async Loading”Use onsearch to load options dynamically. The component debounces search input internally.
No options
View code
<script>import { Select } from '@delightstack/components';
let selected = $state('');let options = $state([]);let isLoading = $state(false);</script>
<Selectsearchableloading={isLoading}onsearch={async ({ query }) => { isLoading = true; options = await searchAPI(query); isLoading = false;}}bind:value={selected}{options}label="Search users"/>Creatable Mode
Section titled “Creatable Mode”Allow users to type new values when no match is found.
Select or create tags...
Featured
New
On Sale
View code
<script> import { Select } from '@delightstack/components';
let selected = $state([]); let tags = $state([ { value: 'featured', label: 'Featured' }, { value: 'new', label: 'New' }, ]);</script>
<Select creatable searchable multiple bind:value={selected} options={tags} label="Tags" oncreate={({ value }) => { tags = [...tags, { value, label: value }]; }}/>With Error
Section titled “With Error”Select a category
Electronics
Clothing
Books
Home & Garden
View code
<Select bind:value={category} options={categories} label="Category" required error={!category ? 'Please select a category' : ''}/>Custom Option Rendering
Section titled “Custom Option Rendering”Use the option snippet to customize how each option appears in the dropdown.
Select a team member
AJ
Alice Johnson
Engineering
BS
Bob Smith
Design
CW
Carol Williams
Marketing
DB
Dave Brown
Sales
View code
<script> import { Select } from '@delightstack/components';
let selectedUser = $state('');
const users = [ { value: 'alice', label: 'Alice Johnson', description: 'Engineering', initials: 'AJ' }, { value: 'bob', label: 'Bob Smith', description: 'Design', initials: 'BS' }, { value: 'carol', label: 'Carol Williams', description: 'Marketing', initials: 'CW' }, { value: 'dave', label: 'Dave Brown', description: 'Sales', initials: 'DB' }, ];</script>
<Select options={users} bind:value={selectedUser} label="Assign to" placeholder="Select a team member"> {#snippet option(opt)} <div style="display: flex; align-items: center; gap: 0.5rem;"> <div style="width: 28px; height: 28px; border-radius: 50%; background: var(--c-primary); color: white; display: flex; align-items: center; justify-content: center; font-size: 0.7rem; font-weight: 600;"> {opt.initials} </div> <div> <span>{opt.label}</span> <span style="font-size: 0.8em; opacity: 0.6;">{opt.description}</span> </div> </div> {/snippet}</Select>Filled
Section titled “Filled”The trigger is transparent (outlined) by default so it sits cleanly on any surface. Set filled to paint a solid surface background behind it.
Transparent surface
United States
Canada
United Kingdom
Solid surface
United States
Canada
United Kingdom
View code
<Select label="Outlined (default)" placeholder="Transparent surface" options={countries} /><Select label="Filled" placeholder="Solid surface" options={countries} filled />| Prop | Type | Default | Description |
|---|---|---|---|
value | unknown | - | Selected value (single or array for multi), bindable |
options | SelectOption[] | [] | Available options |
multiple | boolean | false | Allow multi-select |
searchable | boolean | false | Enable search/filter input |
clearable | boolean | false | Show clear button on trigger |
creatable | boolean | false | Allow creating new options |
loading | boolean | false | Show loading state in dropdown |
disabled | boolean | false | Disable select |
placeholder | string | 'Select...' | Placeholder text |
label | string | - | Field label |
error | string | - | Error message (errors from a parent Form context display automatically) |
parse | (value: unknown) => unknown | - | Validator that throws a user-showable error message. Standalone it runs when the dropdown closes; inside a Form it is registered with the form instead |
description | string | - | Description text below the trigger (hidden while an error shows) |
required | boolean | false | Mark as required |
size | '0' | '1' | '2' | '3' | '1' | Trigger and option size |
skeleton | boolean | false | Show skeleton loading state |
tooltip | string | - | Tooltip text on hover |
dense | boolean | false | Compact option spacing |
comfortable | boolean | false | Relaxed option spacing |
filled | boolean | false | Paint a solid surface background behind the trigger (vs the default transparent/outlined look) |
id | string | auto | Element ID |
name | string | - | Form field name. Inside a Form, registers the field; with no value prop the select becomes context-driven (reads/writes the form data — no bind:value needed) |
class | string | '' | Additional CSS classes |
render_value | Snippet<[selected]> | - | Custom rendering of selected value in trigger |
option | Snippet<[opt]> | - | Custom rendering of each option |
Events
Section titled “Events”| Event | Detail | Description |
|---|---|---|
onchange | { value: unknown } | Selection changed |
onsearch | { query: string } | Search query changed (for async loading) |
oncreate | { value: string } | New value created. Return false to reject |
onopen | - | Dropdown opened |
onclose | - | Dropdown closed |
interface SelectOption { value: unknown; label: string; disabled?: boolean; description?: string; group?: string;}Accessibility
Section titled “Accessibility”- Trigger:
role="combobox",aria-expanded,aria-haspopup="listbox" - Dropdown:
role="listbox" - Options:
role="option",aria-selected - Multi-select:
aria-multiselectable="true"on listbox - Search input:
aria-label="Search options" - Full keyboard navigation: Tab, Arrow keys, Enter to select, Escape to close, Home/End
- Focus management: focus moves to search/first option on open, returns to trigger on close
- Virtual scrolling activates automatically for 100+ options