Combobox

A searchable dropdown component combining input and selection

Basic Usage

Simple combobox with searchable dropdown

Selected framework: None
Selected language: typescript

Code Svelte
1
2<script lang="ts">
3	import { ComboBox } from "@kareyes/aether";
4
5	const frameworks = [
6		{ value: "sveltekit", label: "SvelteKit" },
7		{ value: "next.js", label: "Next.js" },
8		{ value: "nuxt.js", label: "Nuxt.js" },
9		{ value: "remix", label: "Remix" },
10		{ value: "astro", label: "Astro" },
11		{ value: "gatsby", label: "Gatsby" },
12		{ value: "angular", label: "Angular" },
13		{ value: "vue", label: "Vue" },
14		{ value: "react", label: "React" },
15	];
16
17	const languages = [
18		{ value: "javascript", label: "JavaScript" },
19		{ value: "typescript", label: "TypeScript" },
20		{ value: "python", label: "Python" },
21		{ value: "java", label: "Java" },
22		{ value: "csharp", label: "C#" },
23		{ value: "go", label: "Go" },
24		{ value: "rust", label: "Rust" },
25		{ value: "ruby", label: "Ruby" },
26		{ value: "php", label: "PHP" },
27		{ value: "swift", label: "Swift" },
28		{ value: "kotlin", label: "Kotlin" },
29		{ value: "dart", label: "Dart" },
30	];
31
32	let framework = $state("");
33		let language = $state("typescript");
34</script>
35
36	<div class="flex flex-wrap gap-4">
37		<ComboBox
38			items={frameworks}
39			bind:value={framework}
40			placeholder="Select framework..."
41			searchPlaceholder="Search frameworks..."
42		/>
43
44		<ComboBox
45			items={languages}
46			bind:value={language}
47			placeholder="Select language..."
48			searchPlaceholder="Search languages..."
49		/>
50	</div>

Trigger Variants

Different button styles for the combobox trigger


Code Svelte
1
2<script lang="ts">
3	import { ComboBox } from "@kareyes/aether";
4
5	const frameworks = [
6		{ value: "sveltekit", label: "SvelteKit" },
7		{ value: "next.js", label: "Next.js" },
8		{ value: "nuxt.js", label: "Nuxt.js" },
9		{ value: "remix", label: "Remix" },
10		{ value: "astro", label: "Astro" },
11		{ value: "gatsby", label: "Gatsby" },
12		{ value: "angular", label: "Angular" },
13		{ value: "vue", label: "Vue" },
14		{ value: "react", label: "React" },
15	];
16</script>
17
18<div class="flex flex-wrap gap-4">
19	<ComboBox items={frameworks} triggerVariant="default" placeholder="Default" />
20	<ComboBox items={frameworks} triggerVariant="secondary" placeholder="Secondary" />
21	<ComboBox items={frameworks} triggerVariant="outline" placeholder="Outline" />
22	<ComboBox items={frameworks} triggerVariant="ghost" placeholder="Ghost" />
23</div>

Sizes

Three size options: small, default, and large


Code Svelte
1
2<script lang="ts">
3	import { ComboBox } from "@kareyes/aether";
4
5	const frameworks = [
6		{ value: "sveltekit", label: "SvelteKit" },
7		{ value: "next.js", label: "Next.js" },
8	];
9</script>
10
11<div class="flex flex-wrap items-center gap-4">
12	<ComboBox items={frameworks} triggerSize="sm" placeholder="Small" />
13	<ComboBox items={frameworks} triggerSize="default" placeholder="Default" />
14	<ComboBox items={frameworks} triggerSize="lg" placeholder="Large" />
15</div>

Width Options

Customize the width of the trigger and content

Default width (200px)

Medium width (300px)

Full width with auto-size content


Code Svelte
1
2<script lang="ts">
3	import { ComboBox } from "@kareyes/aether";
4
5	const languages = [
6		{ value: "javascript", label: "JavaScript" },
7		{ value: "typescript", label: "TypeScript" },
8		{ value: "python", label: "Python" },
9		{ value: "java", label: "Java" },
10		{ value: "csharp", label: "C#" },
11		{ value: "go", label: "Go" },
12		{ value: "rust", label: "Rust" },
13		{ value: "ruby", label: "Ruby" },
14		{ value: "php", label: "PHP" },
15		{ value: "swift", label: "Swift" },
16		{ value: "kotlin", label: "Kotlin" },
17		{ value: "dart", label: "Dart" },
18	];
19
20	const countries = [
21		{ value: "us", label: "United States" },
22		{ value: "uk", label: "United Kingdom" },
23		{ value: "ca", label: "Canada" },
24		{ value: "au", label: "Australia" },
25		{ value: "de", label: "Germany" },
26		{ value: "fr", label: "France" },
27		{ value: "jp", label: "Japan" },
28		{ value: "cn", label: "China" },
29		{ value: "in", label: "India" },
30		{ value: "br", label: "Brazil" },
31	];
32
33	const timezones = [
34		{ value: "pst", label: "Pacific Standard Time (PST)" },
35		{ value: "mst", label: "Mountain Standard Time (MST)" },
36		{ value: "cst", label: "Central Standard Time (CST)" },
37		{ value: "est", label: "Eastern Standard Time (EST)" },
38		{ value: "utc", label: "Coordinated Universal Time (UTC)" },
39		{ value: "gmt", label: "Greenwich Mean Time (GMT)" },
40		{ value: "ist", label: "Indian Standard Time (IST)" },
41		{ value: "jst", label: "Japan Standard Time (JST)" },
42	];
43
44
45	let language = $state("typescript");
46	let country = $state("");
47	let timezone = $state("utc");
48</script>
49
50	<div class="space-y-4">
51		<div>
52			<p class="text-sm text-muted-foreground mb-2">Default width (200px)</p>
53			<ComboBox
54				items={countries}
55				triggerClass="w-[200px]"
56				contentClass="w-[200px]"
57				placeholder="Select country..."
58			/>
59		</div>
60		<div>
61			<p class="text-sm text-muted-foreground mb-2">Medium width (300px)</p>
62			<ComboBox
63				items={timezones}
64				triggerClass="w-[300px]"
65				contentClass="w-[300px]"
66				placeholder="Select timezone..."
67			/>
68		</div>
69		<div>
70			<p class="text-sm text-muted-foreground mb-2">Full width with auto-size content</p>
71			<ComboBox
72				items={frameworks}
73				triggerClass="w-full"
74				contentClass="w-[var(--bits-popover-trigger-width)]"
75				placeholder="Select framework..."
76			/>
77		</div>
78	</div>

Form Example

Using combobox in a form with labels

Form Values:

Framework: Not selected
Language: typescript
Country: Not selected
Timezone: utc

Code Svelte
1
2<script lang="ts">
3	import { ComboBox, Label } from "@kareyes/aether";
4
5	const frameworks = [
6		{ value: "sveltekit", label: "SvelteKit" },
7		{ value: "next.js", label: "Next.js" },
8		{ value: "nuxt.js", label: "Nuxt.js" },
9		{ value: "remix", label: "Remix" },
10		{ value: "astro", label: "Astro" },
11		{ value: "gatsby", label: "Gatsby" },
12		{ value: "angular", label: "Angular" },
13		{ value: "vue", label: "Vue" },
14		{ value: "react", label: "React" },
15	];
16
17	const languages = [
18		{ value: "javascript", label: "JavaScript" },
19		{ value: "typescript", label: "TypeScript" },
20		{ value: "python", label: "Python" },
21		{ value: "java", label: "Java" },
22		{ value: "csharp", label: "C#" },
23		{ value: "go", label: "Go" },
24		{ value: "rust", label: "Rust" },
25		{ value: "ruby", label: "Ruby" },
26		{ value: "php", label: "PHP" },
27		{ value: "swift", label: "Swift" },
28		{ value: "kotlin", label: "Kotlin" },
29		{ value: "dart", label: "Dart" },
30	];
31
32	const countries = [
33		{ value: "us", label: "United States" },
34		{ value: "uk", label: "United Kingdom" },
35		{ value: "ca", label: "Canada" },
36		{ value: "au", label: "Australia" },
37		{ value: "de", label: "Germany" },
38		{ value: "fr", label: "France" },
39		{ value: "jp", label: "Japan" },
40		{ value: "cn", label: "China" },
41		{ value: "in", label: "India" },
42		{ value: "br", label: "Brazil" },
43	];
44
45	const timezones = [
46		{ value: "pst", label: "Pacific Standard Time (PST)" },
47		{ value: "mst", label: "Mountain Standard Time (MST)" },
48		{ value: "cst", label: "Central Standard Time (CST)" },
49		{ value: "est", label: "Eastern Standard Time (EST)" },
50		{ value: "utc", label: "Coordinated Universal Time (UTC)" },
51		{ value: "gmt", label: "Greenwich Mean Time (GMT)" },
52		{ value: "ist", label: "Indian Standard Time (IST)" },
53		{ value: "jst", label: "Japan Standard Time (JST)" },
54	];
55
56	// State
57	let framework = $state("");
58	let language = $state("typescript");
59	let country = $state("");
60	let timezone = $state("utc");
61</script>
62
63	<div class="max-w-md space-y-4">
64		<div class="space-y-2">
65			<Label class="text-sm font-medium">Framework</Label>
66			<ComboBox
67				items={frameworks}
68				bind:value={framework}
69				placeholder="Select a framework..."
70				searchPlaceholder="Search frameworks..."
71				triggerClass="w-full"
72				contentClass="w-[var(--bits-popover-trigger-width)]"
73			/>
74		</div>
75		<div class="space-y-2">
76			<Label class="text-sm font-medium">Primary Language</Label>
77			<ComboBox
78				items={languages}
79				bind:value={language}
80				placeholder="Select a language..."
81				searchPlaceholder="Search languages..."
82				triggerClass="w-full"
83				contentClass="w-[var(--bits-popover-trigger-width)]"
84			/>
85		</div>
86		<div class="space-y-2">
87			<Label class="text-sm font-medium">Country</Label>
88			<ComboBox
89				items={countries}
90				bind:value={country}
91				placeholder="Select a country..."
92				searchPlaceholder="Search countries..."
93				triggerClass="w-full"
94				contentClass="w-[var(--bits-popover-trigger-width)]"
95			/>
96		</div>
97		<div class="space-y-2">
98			<Label class="text-sm font-medium">Timezone</Label>
99			<ComboBox
100				items={timezones}
101				bind:value={timezone}
102				placeholder="Select a timezone..."
103				searchPlaceholder="Search timezones..."
104				triggerClass="w-full"
105				contentClass="w-[var(--bits-popover-trigger-width)]"
106			/>
107		</div>
108	</div>
109	<div class="mt-6 p-4 bg-muted rounded-lg max-w-md">
110		<h3 class="font-medium mb-2">Form Values:</h3>
111		<div class="text-sm space-y-1">
112			<div>Framework: <span class="font-medium">{framework || "Not selected"}</span></div>
113			<div>Language: <span class="font-medium">{language || "Not selected"}</span></div>
114			<div>Country: <span class="font-medium">{country || "Not selected"}</span></div>
115			<div>Timezone: <span class="font-medium">{timezone || "Not selected"}</span></div>
116		</div>
117	</div>

Custom Trigger

Use the trigger snippet to provide custom trigger elements.


Code Svelte
1
2<script lang="ts">
3	import { ComboBox, Button, PopoverPrimitives as Popover } from "@kareyes/aether";
4	import { ChevronsUpDown } from "@kareyes/aether/icons";
5
6	const frameworks = [
7		{ value: "sveltekit", label: "SvelteKit" },
8		{ value: "next.js", label: "Next.js" },
9		{ value: "nuxt.js", label: "Nuxt.js" },
10		{ value: "remix", label: "Remix" },
11		{ value: "astro", label: "Astro" },
12		{ value: "gatsby", label: "Gatsby" },
13		{ value: "angular", label: "Angular" },
14		{ value: "vue", label: "Vue" },
15		{ value: "react", label: "React" },
16	];
17
18	const languages = [
19		{ value: "javascript", label: "JavaScript" },
20		{ value: "typescript", label: "TypeScript" },
21		{ value: "python", label: "Python" },
22		{ value: "java", label: "Java" },
23		{ value: "csharp", label: "C#" },
24		{ value: "go", label: "Go" },
25		{ value: "rust", label: "Rust" },
26		{ value: "ruby", label: "Ruby" },
27		{ value: "php", label: "PHP" },
28		{ value: "swift", label: "Swift" },
29		{ value: "kotlin", label: "Kotlin" },
30		{ value: "dart", label: "Dart" },
31	];
32	let framework = $state("");
33	let language = $state("typescript");
34</script>
35
36	<div class="flex flex-wrap gap-4">
37		<!-- Custom styled trigger -->
38		<ComboBox items={frameworks} bind:value={framework}>
39			{#snippet trigger({ selectedLabel, open })}
40				<Popover.Trigger>
41					{#snippet child({ props })}
42						<Button
43							{...props}
44							variant="outline"
45							class="w-[280px] justify-between border-2 border-primary/20 hover:border-primary/40"
46							role="combobox"
47							aria-expanded={open}
48						>
49							<span class="flex items-center gap-2">
50								{#if selectedLabel}
51									<span class="w-2 h-2 rounded-full bg-green-500"></span>
52								{/if}
53								{selectedLabel || "Choose your framework..."}
54							</span>
55							<ChevronsUpDown class="ml-2 size-4 shrink-0 opacity-50" />
56						</Button>
57					{/snippet}
58				</Popover.Trigger>
59			{/snippet}
60		</ComboBox>
61
62		<!-- Minimal text trigger -->
63		<ComboBox items={languages} bind:value={language}>
64			{#snippet trigger({ selectedLabel, open })}
65				<Popover.Trigger>
66					{#snippet child({ props })}
67						<button
68							{...props}
69							class="text-sm font-medium text-primary hover:underline cursor-pointer flex items-center gap-1"
70						>
71							{selectedLabel || "Select language"} ▼
72						</button>
73					{/snippet}
74				</Popover.Trigger>
75			{/snippet}
76		</ComboBox>
77	</div>
78

With Disabled Items

Some options can be disabled to prevent selection


Code Svelte
1
2<script lang="ts">
3	import { ComboBox } from "@kareyes/aether";
4</script>
5
6<ComboBox
7	items={[
8		{ value: "option1", label: "Available Option 1" },
9		{ value: "option2", label: "Disabled Option 2", disabled: true },
10		{ value: "option3", label: "Available Option 3" },
11		{ value: "option4", label: "Disabled Option 4", disabled: true },
12		{ value: "option5", label: "Available Option 5" },
13	]}
14	placeholder="Select option..."
15/>