https://github.com/brunnerh/autocomplete
An autocomplete component.
https://github.com/brunnerh/autocomplete
component svelte-component
Last synced: 3 months ago
JSON representation
An autocomplete component.
- Host: GitHub
- URL: https://github.com/brunnerh/autocomplete
- Owner: brunnerh
- License: mit
- Created: 2020-03-04T17:40:48.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2023-05-08T05:23:29.000Z (about 2 years ago)
- Last Synced: 2025-03-17T20:56:27.424Z (3 months ago)
- Topics: component, svelte-component
- Language: HTML
- Homepage:
- Size: 770 KB
- Stars: 3
- Watchers: 1
- Forks: 1
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Autocomplete Component
An autocomplete component which can be used as a regular ES module import or as a [*Svelte*][svelte] component.
It has no dependencies, handles synchronous and asynchronous data sources, supports item templating and escapes any HTML automatically.
([Change log][changelog])
## Install
```
npm install @brunnerh/autocomplete
```## Usage
In a *Svelte* project the component can be imported in a `` section and then used in the HTML like any other:
```html
<script>
// (Named import!)
import { AutoComplete } from '@brunnerh/autocomplete';const items = ['Apple', 'Orange', 'Pear'];
items}/>
```In any other type of project, the component can be instantiated in the script:
```html
import { AutoComplete } from '@brunnerh/autocomplete';
const items = ['Apple', 'Orange', 'Pear'];
new AutoComplete({
target: document.querySelector('#autocomplete-target'),
props: { items: () => items },
});```
For documentation of how to interact with component instances see [Client-side component API][client-side-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](#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](#items-property). |
| `value` | `any` | `null` | Gets the last selected value. See [Items Property](#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](#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.:
```html
// Fetch once:
const suggestions = fetch('/api/items');suggestions}/>
```The items have to be strings or of the form:
```typescript
{
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:
```typescript
(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) |#### `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:
```typescript
{
/** 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:
```html
data} let:result>
{result.index + 1}: {@html result.label}
({result.value})
```
## 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` => `Apple`### 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][1] ([License][1l]) - Repo built on template.
- [elcobvg/svelte-autocomplete][2] ([License][2l]) - Original code-base.[changelog]: https://github.com/brunnerh/autocomplete/blob/master/CHANGELOG.md
[svelte]: https://svelte.dev/
[client-side-api]: https://svelte.dev/docs#Client-side_component_API
[1]: https://github.com/patoi/svelte-component-library-template
[1l]: https://github.com/patoi/svelte-component-library-template/blob/master/LICENSE
[2]: https://github.com/elcobvg/svelte-autocomplete
[2l]: https://github.com/elcobvg/svelte-autocomplete/blob/master/LICENSE