Autocomplete Component
An autocomplete component which can be used as a regular ES module import or as a Svelte component.
It has no dependencies, handles synchronous and asynchronous data sources, supports item templating and escapes any HTML automatically.
Install
npm install @brunnerh/autocomplete
Usage
In a Svelte project the component can be imported in a <script>
section and then used in the HTML like any other:
<script>
// (Named import!)
import { AutoComplete } from '@brunnerh/autocomplete';
const items = ['Apple', 'Orange', 'Pear'];
</script>
<AutoComplete items={() => items}/>
In any other type of project, the component can be instantiated in the script:
<div id="autocomplete-target"></div>
<script type="module">
import { AutoComplete } from '@brunnerh/autocomplete';
const items = ['Apple', 'Orange', 'Pear'];
new AutoComplete({
target: document.querySelector('#autocomplete-target'),
props: { items: () => items },
});
</script>
For documentation of how to interact with component instances see Client-side component API in the Svelte docs.
Properties
Prop | Type | Default | Description |
---|---|---|---|
id |
string | null |
null |
Sets the id of the input element. |
name |
string | null |
null |
Sets the name of the input element. |
className |
string |
'' |
Sets additional class name/names of the input element (should be space separated). |
placeholder |
string | null |
null |
Sets the placeholder of the input element. |
title |
string | null |
null |
Sets the title of the input element. |
required |
boolean |
false |
Sets the required attribute on the input element if true . |
disabled |
boolean |
false |
Sets the disabled attribute on the input element if true . |
tabindex |
number | undefined |
undefined |
Sets the tabindex attribute on the input element. |
autoScroll |
boolean |
true |
Automatically scrolls the component into view. Can be helpful if the component is at the bottom a scrollable area and the dropdown ends up off-screen. |
autoScrollCursor |
boolean |
true |
Automatically scrolls to the cursor position in the list. Turn off if there are performance issues. |
items |
() => Item[] |
Sets the suggestions. See Items Property. | |
isOpen |
boolean |
false |
Gets or sets whether the suggestions dropdown is open. |
key |
any |
null |
Gets the last selected key. See Items Property. |
value |
any |
null |
Gets the last selected value. See Items Property. |
results |
any[] |
[] |
Gets the subset of items that match the user input, reduced to the first maxItems items. |
search |
string |
'' |
Gets or sets the current search term/input value. |
isLoading |
boolean |
false |
Gets whether the component is currently loading the suggestions (if items returns a promise). |
cursor |
number |
0 |
Gets or sets the index of the currently highlighted item within the suggestions list. |
cursorItem |
any |
undefined |
Gets the currently highlighted item. |
maxItems |
number? |
undefined |
Sets the maximal number of items to show in suggestions list at a time. |
fromStart |
boolean |
false |
Sets whether the search string has to appear at the start of the item. |
caseSensitive |
boolean |
false |
Sets whether the search is case-sensitive. |
minChar |
number |
0 |
Sets the minimum number of characters required to trigger a search. |
debounce |
number |
0 |
Sets the time to wait in milliseconds before triggering a search. |
blindSelection |
boolean |
false |
Sets whether suggested items are directly selected upon pressing arrow up/down while the dropdown is closed. |
lazyDropdown |
boolean |
false |
Whether the DOM elements for the suggestions list are only created upon filtering/opening the suggestions dropdown. |
searchRegEx |
(search: string) => RegExp | null |
null |
Custom search RegEx generator. If set, fromStart and caseSensitive will not be used. |
searchFunction |
Search Function | null |
Custom search function. See Search Function Property. |
Items Property
The items
property has to be a function returning a list of items for the auto-completion.
The return value can be a promise to load data asynchronously. Returning an existing promise if the list of suggestions can be cached is recommended. E.g.:
<script>
// Fetch once:
const suggestions = fetch('/api/items');
</script>
<AutoComplete items={() => suggestions}/>
The items have to be strings or of the form:
{
key: string,
value?: any,
}
The key will be used for the search and displayed in the suggestions dropdown by default.
The value
represents a technical item value that is assigned to the value
property of the component upon selection. If no value is set, the whole item will be assigned.
For strings, the string will serve as key and value.
Search Function Property
The property searchFunction
can be used to provide custom search logic when a custom regular expression (searchRegEx
) is not enough.
The type of the function is as follows:
(search: string) => (text: string) => {
/** Whether the item `text` matches `search`. */
matches: boolean,
/**
* An array of start and end index tuples for parts of the text that should be highlighted as matching.
* Should be an empty array if nothing matches or no highlighting should be shown.
*/
highlights: [number, number][],
}
If set, fromStart
, caseSensitive
and searchRegEx
will not be used.
Events
The following events are emitted by the component, event data/forwarded event can be found in the detail
property:
Type | Description |
---|---|
filtered |
Fired after the suggestion list has been filtered. |
item-selected |
Fired upon item selection, either by pressing Enter or clicking on one. The event data is the selected item. |
focus |
Forwarded from input. |
blur |
Forwarded from input. |
input |
Forwarded from input. |
keydown |
Forwarded from input. |
click |
Forwarded from input. |
Slots
The following slots can be used in Svelte projects:
Name | Injected Props | Description |
---|---|---|
loading |
The loading indicator that is displayed while items are loading asynchronously. Default: Loading data...
|
|
template |
result |
A custom template for rendering the items. See Template |
template
By default, items show the item key
with matching parts of the text highlighted. This slot can be used to customize this output.
The injected result
prop has the following type:
{
/** The index of the item in the filtered results list (0-based). */
index: number,
/** The key of the item. Either the `key` property or the item itself, if it a string. */
key: string,
/** The value of the item. Either the `value` property or the whole item. */
value: any,
/** An HTML string that contains highlighted parts in spans with the class `ac-match`. */
label: string,
}
Example:
<AutoComplete items={() => data} let:result>
<!-- Renders item with index prefix and value in parentheses on a second line. -->
<div slot="template">
{result.index + 1}: {@html result.label}
<br/>
<span style="font-size: smaller; opacity: 0.7">({result.value})</span>
</div>
</AutoComplete>
Styling
The component comes with a default style and defines various CSS custom properties to make theming easier.
It can also be styled via the classes of the various parts.
Structure
.autocomplete
input.autocomplete-input
.autocomplete-results-dropdown
.autocomplete-loading
ul.autocomplete-results-list
li.autocomplete-result[.ac-highlighted]
span[.ac-match]
-
ac-highlighted
is applied to the item highlighted via arrow/up or mouse hover. -
ac-match
is applied to the parts of the item text that match the search.- E.g.: Search:
ap
, item text:Apple
=><span class="ac-match">Ap</span>ple
- E.g.: Search:
CSS Custom Properties
Target | Name | Default Value |
---|---|---|
.autocomplete-input |
--ac-input-color |
black |
.autocomplete-input |
--ac-input-background |
white |
.autocomplete-input |
--ac-input-border |
1px solid hsl(0, 0%, 60%) |
.autocomplete-input |
--ac-input-border-radius |
0 |
.autocomplete-input |
--ac-input-padding |
3px |
.autocomplete-input |
--ac-input-margin |
0 |
.autocomplete-input |
--ac-input-font-size |
small |
.autocomplete-input |
--ac-input-font-weight |
normal |
.autocomplete-results-dropdown |
--ac-dropdown-color |
Fallback: --ac-input-color
|
.autocomplete-results-dropdown |
--ac-dropdown-background |
Fallback: --ac-input-background
|
.autocomplete-results-dropdown |
--ac-dropdown-box-shadow |
0px 2px 5px hsla(0, 0%, 0%, 0.7) |
.autocomplete-results-dropdown |
--ac-dropdown-margin: |
0 |
.autocomplete-results-dropdown |
--ac-dropdown-padding: |
0 |
.autocomplete-results-dropdown |
--ac-dropdown-border-radius |
0 |
.autocomplete-loading |
--ac-loading-color |
inherit |
.autocomplete-loading |
--ac-loading-background |
none |
.autocomplete-loading |
--ac-loading-padding |
0 |
.autocomplete-loading |
--ac-loading-margin |
5px |
.autocomplete-result |
--ac-result-color |
inherit |
.autocomplete-result |
--ac-result-background |
none |
.autocomplete-result |
--ac-result-border |
none |
.autocomplete-result |
--ac-result-margin |
0 |
.autocomplete-result |
--ac-result-padding |
0.2em 0.5em |
.autocomplete-result |
--ac-result-border-radius |
0 |
.autocomplete-result.ac-highlighted |
--ac-result-highlighted-color |
inherit + Fallback: --ac-result-color
|
.autocomplete-result.ac-highlighted |
--ac-result-highlighted-background |
#dbdbdb + Fallback: --ac-result-background
|
.autocomplete-result.ac-highlighted |
--ac-result-highlighted-border |
Fallback: --ac-result-border
|
.autocomplete-result.ac-highlighted |
--ac-result-highlighted-margin |
Fallback: --ac-result-margin
|
.autocomplete-result.ac-highlighted |
--ac-result-highlighted-padding |
Fallback: --ac-result-padding
|
.autocomplete-result.ac-highlighted |
--ac-result-highlighted-border-radius |
Fallback: --ac-result-border-radius
|
.autocomplete-result .ac-match |
--ac-result-match-color |
inherit |
.autocomplete-result .ac-match |
--ac-result-match-background |
none |
.autocomplete-result .ac-match |
--ac-result-match-border-radius |
0 |
.autocomplete-result .ac-match |
--ac-result-match-font-weight |
bold |
.autocomplete-result .ac-match |
--ac-result-match-font-style |
inherit |
Attribution
- patoi/svelte-component-library-template (License) - Repo built on template.
- elcobvg/svelte-autocomplete (License) - Original code-base.