Accessible, fuzzy search typeahead component.
This component uses the lightweight fuzzy library for client-side, fuzzy search and follows WAI-ARIA guidelines.
Try it in the Svelte REPL.
yarn add -D svelte-typeahead
# OR
npm i -D svelte-typeahead
svelte-search is used as the underlying search input component. $$restProps
are forwarded to svelte-search
.
Note: this component is minimally styled by design. You can target the component using the [data-svelte-typeahead]
selector.
:global([data-svelte-typeahead]) {
margin: 1rem;
}
Pass an array of objects to the data
prop. Use the extractor
to specify the key value to search on.
<script>
import Typeahead from "svelte-typeahead";
const data = [
{ id: 0, state: "California" },
{ id: 1, state: "North Carolina" },
{ id: 2, state: "North Dakota" },
{ id: 3, state: "South Carolina" },
{ id: 4, state: "South Dakota" },
{ id: 5, state: "Michigan" },
{ id: 6, state: "Tennessee" },
{ id: 7, state: "Nevada" },
{ id: 8, state: "New Hampshire" },
{ id: 9, state: "New Jersey" },
];
const extract = (item) => item.state;
</script>
<Typeahead {data} {extract} />
By default, this component uses the fuzzy
library to highlight matching characters with the mark
element.
Use a slot to render custom results.
<Typeahead {data} {extract} let:result let:index>
<div style="color: red; font-weight: bold;">
{@html result.string}
{index}
</div>
</Typeahead>
Use the limit
prop to specify the maximum number of results to display. The default limit is Infinity
.
<Typeahead limit={2} {data} {extract} />
Use the filter
to filter Items out and disable
to disable them in the result set.
Example for disabling and filtering items by their title length:
<script>
const disable = (item) => item.state.length > 4;
const filter = (item) => item.state.length > 8;
</script>
<Typeahead {data} extract={(item) => item.state} {disable} {filter} />
Example for disabling items after selecting them:
<script>
function handleSelect(e) {
let i = e.detail.originalIndex;
data[i].selected = true;
}
</script>
<Typeahead
{data}
extract={(item) => item.state}
disable={(item) => item.selected}
on:select={handleSelect}
/>
Set focusAfterSelect
to true
to re-focus the search input after selecting a result.
<Typeahead focusAfterSelect {data} {extract} />
Prop name | Value | Description |
---|---|---|
value | string (default: "" ) |
Input search value |
data | T[] (default: [] ) |
Items to search |
extract | (T) => T |
Target an item key if data is an object array |
disable | (T) => T |
Pass in a function to disable items. They will show up in the results list, but wont be selectable. |
filter | (T) => T |
Pass in a function to filter items. Thei will be hidden and do not show up at all in the results list. |
autoselect | boolean (default: true ) |
Automatically select the first (top) result |
inputAfterSelect | "update" or "clear" or "keep" (default:"update" ) |
Set to "clear" to clear the value after selecting a result. Set to "keep" keep the search field unchanged after a selection. |
results | FuzzyResult[] (default: [] ) |
Raw fuzzy results from the fuzzy module |
focusAfterSelect | boolean (default: false ) |
Set to true to re-focus the input after selecting a result. |
limit | number (default: Infinity ) |
Specify the maximum number of results to return |
...$$restProps |
(forwarded to Search component) |
All other props are forwarded to the input element. |
- on:select: dispatched when selecting a result
- on:clear: dispatched when clearing the input field
<script>
let events = [];
function update(event, detail) {
events = [...events, JSON.stringify({ event, detail }, null, 2)];
}
</script>
<Typeahead
{data}
{extract}
on:select={(e) => {
update("select", e.detail);
}}
on:clear={() => {
update("clear");
}}
/>
<ul>
{#each events as event}
<li>
<pre>{event}</pre>
</li>
{/each}
</ul>
The following events are forwarded to the svelte-search component.
- on:type
- on:input
- on:change
- on:focus
- on:clear
- on:blur
- on:keydown
To use this component with svite, add the following to your vite.config.js
:
// vite.config.js
module.exports = {
optimizeDeps: {
include: ["fuzzy"],
},
};
Svelte version 3.31 or greater is required if using TypeScript.