Skip to content
Inputs

Combobox

Combobox — type to search, arrow to the one you want, Enter to take it.

Walkthrough

1. Basic

Type to filter, arrow to the one you want, Enter to take it — the field for a list too long to scroll, like a country or a person.

<script lang="ts">	import { Combobox } from 'omaris';​	let country = $state('iq');​	const COUNTRIES = [		{ value: 'iq', label: 'Iraq', keywords: ['baghdad', 'erbil'] },		{ value: 'tr', label: 'Türkiye', keywords: ['turkey', 'ankara'] },		{ value: 'jo', label: 'Jordan', keywords: ['amman'] },		{ value: 'ae', label: 'United Arab Emirates', keywords: ['dubai', 'uae'] },		{ value: 'sa', label: 'Saudi Arabia', keywords: ['riyadh'] }	];</script>​<Combobox class="w-72 max-w-full" label="Country" options={COUNTRIES} bind:value={country} />

2. Keywords

Matching is accent-insensitive and looks at keywords as well as the label, so "turkey" finds Türkiye and "uae" finds the Emirates.

<script lang="ts">	import { Combobox } from 'omaris';​	let value = $state('');​	const AIRPORTS = [		{ value: 'bgw', label: 'Baghdad International', description: 'BGW', keywords: ['iraq'] },		{			value: 'ebl',			label: 'Erbil International',			description: 'EBL',			keywords: ['iraq', 'hawler']		},		{			value: 'ist',			label: 'İstanbul Airport',			description: 'IST',			keywords: ['turkey', 'istanbul']		},		{			value: 'dxb',			label: 'Dubai International',			description: 'DXB',			keywords: ['uae', 'emirates']		}	];</script>​<Combobox	class="w-80 max-w-full"	label="Airport"	placeholder="Try “turkey” or “uae”"	options={AIRPORTS}	bind:value/>

3. Async

load is called instead of filtering, debounced, with an AbortSignal — so a slow reply for "ir" can never overwrite the answer for "iraq".

<script lang="ts">	import { Combobox } from 'omaris';​	let value = $state('');​	const PEOPLE = [		{ value: 'ahmed', label: 'Ahmed' },		{ value: 'amina', label: 'Amina' },		{ value: 'dilan', label: 'Dilan' },		{ value: 'hevi', label: 'Hevi' },		{ value: 'karwan', label: 'Karwan' },		{ value: 'layla', label: 'Layla' },		{ value: 'omer', label: 'Omer' },		{ value: 'rania', label: 'Rania' },		{ value: 'zainab', label: 'Zainab' }	];​	async function search(query: string, signal: AbortSignal) {		// Stand-in for a real request; the signal is what makes it cancellable.		await new Promise((resolve) => setTimeout(resolve, 400));		signal.throwIfAborted();		return PEOPLE.filter((person) => person.label.toLowerCase().includes(query.toLowerCase()));	}</script>​<Combobox	class="w-72 max-w-full"	label="Assign to"	placeholder="Start typing a name"	load={search}	minChars={1}	bind:value/>

4. Allow custom

allowCustom takes whatever is typed when nothing matches — tags, labels.

Nothing chosen yet.

<script lang="ts">	import { Combobox } from 'omaris';​	let tag = $state('');​	const TAGS = [		{ value: 'bug', label: 'bug' },		{ value: 'docs', label: 'docs' },		{ value: 'design', label: 'design' }	];</script>​<Combobox	class="w-72 max-w-full"	label="Tag"	placeholder="Pick one or invent one"	options={TAGS}	allowCustom	bind:value={tag}	supportingText={tag ? `Value: ${tag}` : 'Nothing chosen yet.'}/>

5. Overridden

Combobox is an Input frame with the shared Listbox under it, so it takes both sets of parts: control is the text field, option a row of the popup.

<script lang="ts">	import { Combobox } from 'omaris';​	const CODES = [		{ value: 'iq', label: 'IQ +964' },		{ value: 'tr', label: 'TR +90' },		{ value: 'ae', label: 'AE +971' }	];</script>​<Combobox	class="w-64 max-w-full"	label="Dial code"	options={CODES}	value="iq"	classes={{ control: 'font-mono', option: 'font-mono' }}/>