Overview
SvelteTypeahead renders a text input that opens a floating menu below it,
filtered as the user types - no full-screen modal, no scroll-lock. All state and logic
lives in a plain Typeahead class backed by Svelte stores, so the component itself stays a thin view
over that state.
Installation
yarn add @whizzes/svelte-typeaheadUsage
<script lang="ts">
import { SvelteTypeahead } from '@whizzes/svelte-typeahead';
let selected = $state([]);
</script>
<SvelteTypeahead
id="skills"
options={['Rust', 'TypeScript', 'Svelte', 'Go']}
bind:selected
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | - | Required. Derives the input, listbox and option element ids. |
options | TypeaheadOption[] | [] | The full candidate list - a string, or an object read via labelKey. |
selected | TypeaheadOption[] | [] | The current selection. Bindable with bind:selected. |
multiple | boolean | false | Allow more than one selection, rendered as removable tokens. |
labelKey | string | (option) => string | 'label' | Field (or accessor) read off an object option for display/filtering. |
filterBy | (option, text) => boolean | case/diacritic match | Custom filter predicate, replacing the default one. |
allowNew | boolean | false | Lets the user select their typed text as a new, synthetic option. |
onSearch | (query: string) => void | - | When set, filtering is delegated to the consumer (async mode). |
onchange | (selected: TypeaheadOption[]) => void | - | Fires on selection/removal/clear caused by user interaction. |
theme | Partial<TypeaheadTheme> | DEFAULT_TYPEAHEAD_THEME | Overrides any subset of the visual theme - see Theming below. |
See the full prop list in the README for every option (id, valueKey, disabled, clearButton, isLoading, minLength, newSelectionPrefix, emptyLabel, searchText, searchDelay, name, class).
Theming
Every visual aspect is a CSS custom property, set via the theme prop - only pass
the fields you want to override:
<SvelteTypeahead theme={{ accentColor: '#059669', activeBackground: '#059669' }} /> | Field | Default |
|---|---|
textColor | #111827 |
mutedTextColor | #6b7280 |
placeholderColor | #9ca3af |
borderColor | #d1d5db |
borderRadius | 0.375rem |
accentColor | #4f46e5 |
activeBackground | #4f46e5 |
activeTextColor | #ffffff |
inputBackground | #ffffff |
menuBackground | #ffffff |
menuShadow | 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -4px rgba(0,0,0,.1) |
tokenBackground | #eef2ff |
tokenTextColor | #4338ca |
tokenBorderColor | #c7d2fe |
highlightBackground | #fef08a |
fontFamily | sans-serif |
fontSize | 1rem |
Playground
Tweak the props below and watch the live instance update.
Picked: []
Examples
Single selection
Picked: -
Multiple selection
Picked: -
Object options (labelKey/valueKey)
Picked: -
allowNew (free text)
Picked: -
Async search (onSearch)
Filters asyncResults on a 400ms debounce.
Disabled
A pre-filled, non-interactive instance.