Getting Started
To use AutoComple on your site, you need to import JavaScript/CSS assets and to instantiate the main class
with an HTMLElement
.
Installation
Install AutoComplete from npm package manager:
npm install @loicblascos/autocomplete --save
Import
You can import polyfills, style and main class from package as follows:
import '@loicblascos/autocomplete/lib/polyfills'; // Optional
import '@loicblascos/autocomplete/lib/style.css'; // Optional
import AutoComplete from '@loicblascos/autocomplete';
Assets
If you do not use import, you need to include AutoComplete assets in the document:
<link rel="stylesheet" href="autocomplete.css">
<script src="autocomplete.js" async></script>
Markup
AutoComplete script works with search and text input elements. Explicit and Implicit input labels are supported by AutoComplete script to be fully accessible.
<!-- Explicit label -->
<label for="my-input">Input Label</label>
<input type="text" id="my-input" placeholder="type to search">
<!-- Implicit label -->
<label>
Input Label
<input type="text" id="my-input" placeholder="type to search">
</label>
Initialize
The AutoComplete()
constructor accepts two arguments: the input element and an options object.
const input = document.querySelector( '#my-input' );
const acplt = new AutoComplete(
input,
{
source: [
{ label: 'label 1', value: 'value 1' },
{ label: 'label 2', value: 'value 2' },
{ label: 'label 3', value: 'value 3' },
],
minLength: 1,
maxResults: 50,
autoSearch: true,
}
);
Options
AutoComplete comes with plenty options to easily customize and extend possibilities.
Property | Type | Default | Description |
---|---|---|---|
source | {Object[]|fn} | [] | Holds list of suggestions to search for. |
minLength | {number} | 1 | Minimum number of characters to trigger a search. |
maxResults | {number} | -1 | Maximum number of suggestions to display in the list. |
regExp | {string} | ($1) | Expression used to match string(s) in suggestion. |
filterResults | {function} | @see doc | Function used to filter suggestions in the list. |
sortResults | {function} | @see doc | Function used to sort suggestions in the list. |
renderItem | {function} | @see doc | Function used to render suggestion in list item. |
highlighter | {HTMLElement} | @see doc | Element used to append matched string(s). |
menuTarget | {HTMLElement} | @see doc | Element used to append autocomplete menu. |
smartAccent | {boolean} | false | Only match accents from searched string. |
matchAll | {boolean} | false | Highlight all matches string in suggestion. |
autoFocus | {boolean} | true | Automatically focus first suggestion in the list. |
autoSearch | {boolean} | false | Automatically searches for suggestions on focus. |
autoComplete | {boolean} | false | Inline auto complete first suggestion while typing. |
loader | {boolean} | false | Display a loader while searching in source (async). |
clearable | {boolean} | true | Display a button with cross icon to clear the field. |
clearLabel | {string} | Clear field | Accessible button label used in clear button. |
classes | {Object} | @see doc | Class names used in AutoComplete elements. |
messages | {Object} | @see doc | Accessible texts appended during user interactions. |
source
AutoComplete source
option accepts an array of strings, an array of objects. When using array of objects, label
is used in suggestion and value
set as input value on selection.
// Array of strings example.
new AutoComplete(
input,
{
source: [ 'value 1', 'value 2', 'value 3' ],
}
);
// Array of objects example.
new AutoComplete(
input,
{
source: [
{ label: 'label 1', value: 'value 1' },
{ label: 'label 2', value: 'value 2' },
{ label: 'label 3', value: 'value 3' },
],
}
);
When using array of objects, you can pass other properties and use them in the option renderItem
. It can be useful to create custom markup with custom content that should not be directly searched.
If you need to make some data preprocessing or make asynchronous request to output suggestions, you can use a function and call the response callback passed as argument:
new AutoComplete(
input,
{
/**
* Return suggestions after a search
*
* @param {string} value - Searched value.
* @param {function} response - Callback function.
*/
source: function( value, response ) {
fetch( `https://api.github.com/search/repositories?q=${value}` )
.then( obj => obj.json() )
.then( data => {
const source = data.items.map( item => item.full_name );
response( source );
} );
},
loader: true,
}
);
filterResults
By default, results from suggestions are filtered by the label. You can use this option to add extra logic to match searched value in suggestions.
const menuTarget = document.querySelector( '.menu-target' );
new AutoComplete(
input,
{
source: [ /* ... */ ],
/**
* Filter by suggestion label and value
*
* @param {boolean} exists - Whether label matches value.
* @param {object} suggestion - label and value.
* @param {string} value - Searched value.
* @param {boolean} Return true to keep the suggestion, false otherwise.
*/
filterResults: function( exists, suggestion, value ) {
// We normalize suggestion value (to remove diacritics, to trim, and to lower case)
// And use regular expression generated from searched value.
return exists || !! this.normalize( suggestion.value ).match( this.regExp );
}
}
);
sortResults
By default, suggestions are sorted by relevance. It means that suggestions are firstly ordered by matched string position, then alphabetically and by suggestion length. If you do not want to sort results you can simply set this option to false
.
new AutoComplete(
input,
{
source: [ /* ... */ ],
// Default function used to sort.
sortResults: ( a, b ) => {
return (
a.index - b.index || // Sort by matched index.
a.label.localeCompare( b.label ) || // Then, sort alphabetically.
a.label.length - b.label.length // Then, sort by string length.
);
}
}
);
renderItem
By default, suggestions output string in list item and cannot output HTML for performance and security reasons (XSS vulnerability from remote source for example). However, you can control the rendered content in each list item thanks to this option.
renderItem
option accepts a function with as arguments the suggestion (from source) and the item element from the list. The function should return an HTMLelement or string to append in the list item. By returning null
it will skip the item from the list.
const colorSwatch = document.createElement( 'span' );
new AutoComplete(
input,
{
source: [
{ label: '#f0f8ff - aliceblue', value: '#f0f8ff' },
{ label: '#faebd7 - antiquewhite', value: '#faebd7' },
{ label: '#00ffff - aqua', value: '#00ffff' },
{ label: '#7fffd4 - aquamarine', value: '#7fffd4' },
{ label: '#f0ffff - azure', value: '#f0ffff' },
{ label: '#f5f5dc - beige', value: '#f5f5dc' },
{ label: '#ffe4c4 - bisque', value: '#ffe4c4' },
{ label: '#000000 - black', value: '#000000' },
/* ... */
],
maxResults: 50,
renderItem: ( suggestion, item ) => {
// We append color swatch directly in list item.
item.append( colorSwatch.cloneNode() );
// We set css variable on list item.
item.style.setProperty( '--color', suggestion.value );
// We return the highlighted suggestion content to append in item.
// Content is a documentFragment because highlight option is enabled.
// Otherwise it'll be a string and it'll erase our appended element.
return suggestion.content;
}
}
);
.acplt-list .acplt-item[style^="--color"] {
display: flex;
color: black;
font-family: monospace;
white-space: pre;
}
.acplt-list .acplt-item[style^="--color"] span {
width: 1rem;
height: 1rem;
margin-right: 0.5rem;
background-color: var(--color);
border-radius: 100%;
box-shadow: 0 0 0 1px #e6ecf1;
}
highlighter
By default, the highlighter use a <mark>
element to append matched string(s), from searched value, in suggestions. You can use any HTMLElement to highlight matched string(s) in suggestion. highlighter
can be set to false
to disable this feature.
const highlighter = document.createElement( 'mark' );
highlighter.className = 'highlighter';
new AutoComplete(
input,
{
source: [ /* ... */ ],
highlighter,
}
);
.acplt-item .highlighter {
background-color: #85ffff;
}
.acplt-item .highlighter::before,
.acplt-item .highlighter::after {
content: "ยท";
background-color: white;
}
.acplt-item[aria-selected=true] .highlighter::before,
.acplt-item[aria-selected=true] .highlighter::after {
background-color: #e9f2ff;
}
menuTarget
By default, the menu is appended in document.body
element. But, it may conflict with your layout, so you can set the element in which you want to append the menu thanks to this option. By changing the menu target and by playing on menu style it's even possible to inline it in the document.
const menuTarget = document.querySelector( '.menu-target' );
new AutoComplete(
input,
{
source: [ /* ... */ ],
menuTarget,
minLength: 0,
maxResults: 5,
autoSearch: true,
onResize: ( { style } ) => {
style.position = 'relative';
style.zIndex = 0;
style.left = 0;
style.top = 0;
},
}
);
classes
Because conflicts may happen with class names or simply because you need to use others, you can replace all classes used by the script thanks to this options:
new AutoComplete(
input,
{
// Default classes.
classes: {
wrapper: 'acplt',
menu: 'acplt-menu',
list: 'acplt-list',
item: 'acplt-item',
clear: 'acplt-clear',
loader: 'acplt-loader',
message: 'acplt-message',
},
}
);
messages
AutoComplete script is accessible and follows W3 ARIA practices. It appends messages on user interactions that can be announced by assistive technologies. You can easily localize these messages thanks to this option:
new AutoComplete(
input,
{
// Default messages.
messages: {
open: 'Use Up and Down to choose suggestions and press Enter to select suggestion.',
input: 'Type to search or press Escape to clear the input.',
clear: 'Field cleared.',
select: '%s suggestion was selected.',
noResults: 'No suggestions found.',
loading: 'Loading suggestions...',
},
}
);
Methods
AutoComplete comes with several public methods that you can call at any time after instantiation. The following methods allow to programmatically interact with input and menu.
Name | Argument | Type | Description |
---|---|---|---|
destroy | - | - | Remove functionalities and instance attached to the input. |
enable | - | - | Remove disable attribute from input and allow search. |
disable | - | - | Add disable attribute and prevent user to search. |
open | - | - | Open menu of suggestions from the last search. |
close | - | - | Close menu of suggestions. |
clear | - | - | Clear input value, close menu and update state. |
search | value | {string} | Trigger a manual search from a string. |
select | index | {number} | Select a suggestion in the menu from an index. |
highlight | index | {number} | Highlight a suggestion in the menu from an index. |
destroy()
Remove AutoComplete functionality and instance attached to the input. destroy()
will return the element back to its pre-initialized state.
const init = document.querySelector( '#init-btn' );
const destroy = document.querySelector( '#destroy-btn' );
const instantiate = () => instance = new AutoComplete( input, { source: [ /* ... */ ] } );
let instance;
instantiate();
init.addEventListener( 'click', instantiate );
destroy.addEventListener( 'click', () => instance && instance.destroy() );
enable() / disable()
While it's possible to directly disable/enable the input with disabled
attribute, these methods will handle other aspects like closing the menu or updating clear button.
const enable = document.querySelector( '#enable-btn' );
const disable = document.querySelector( '#disable-btn' );
const instance = new AutoComplete( input, { source: [ /* ... */ ] } );
enable.addEventListener( 'click', () => instance.enable() );
disable.addEventListener( 'click', () => instance.disable() );
open() / close()
open
method allows to open suggestions from last search if it exists. In this example, we populate the list of suggestion from empty searched string to simulate a search history.
const open = document.querySelector( '#open-btn' );
const close = document.querySelector( '#close-btn' );
const instance = new AutoComplete( input, { source: [ /* ... */ ] } );
// We populate the list of suggestions for demo purpose.
instance.populate( '', instance.options.source );
open.addEventListener( 'click', () => instance.open() );
close.addEventListener( 'click', () => instance.close() );
search() / clear()
search()
method accepts as argument a string to programmatically trigger a search from a string. It allows to search in suggestions and to open menu if there are results. You can also use clear()
method to clear a search (clear input value and close menu).
const search = document.querySelector( '#search-btn' );
const clear = document.querySelector( '#clear-btn' );
const instance = new AutoComplete( input, { source: [ /* ... */ ] } );
search.addEventListener( 'click', () => {
input.value = 'saint';
instance.search( 'saint' );
} );
clear.addEventListener( 'click', () => instance.clear() );
select() / highlight()
select()
and highlight()
methods accept as argument a number to programmatically select or highlight a suggestion from an index.
const select = document.querySelector( '#select-btn' );
const moveUp = document.querySelector( '#moveup-btn' );
const moveDown = document.querySelector( '#movedown-btn' );
const menuTarget = document.querySelector( '#menu-target' );
const instance = new AutoComplete(
input,
{
source: [ /* ... */ ],
menuTarget,
minLength: 0,
maxResults: 20,
onResize: ( { style } ) => {
style.position = 'relative';
style.zIndex = 0;
style.left = 0;
style.top = 0;
},
}
);
// For demo purpose.
instance.close = () => null;
instance.disable();
instance.search();
select.addEventListener( 'click', () => instance.select( instance.index ) );
moveUp.addEventListener( 'click', () => instance.highlight( instance.index - 1 ) );
moveDown.addEventListener( 'click', () => instance.highlight( instance.index + 1 ) );
Events
AutoComplete comes with several events triggered after actions that you can easily capture.
Name | Argument | Type | Description |
---|---|---|---|
onOpen | - | - | Triggered after the menu was opened. |
onClose | - | - | Triggered after the menu was closes. |
onResize | - | - | Triggered after the menu is resized. |
onSearch | value | {string} | Triggered before a search is performed. |
onAbort | - | - | Triggered when a search is aborted (async). |
onClear | - | - | Triggered after the input has been cleared. |
onSelect | item | {Object} | Triggered after a suggestion has been selected. |
onHighlight | item | {object} | Triggered after a suggestion has been highlighted. |
Events Logger
### Events Logger ###

new AutoComplete(
input,
{
source: [ /* ... */ ],
onOpen: () => console.log( 'menu opened' ),
onClose: () => console.log( 'menu closed' ),
onResize: () => console.log( 'menu resized' ),
onSearch: value => console.log( `search for "${ value }"` ),
onAbort: () => console.log( 'search aborted' ),
onClear: () => console.log( 'input cleared' ),
onSelect: item => console.log( `"${ item.label }" selected` ),
onHighlight: item => console.log( `"${ item.label }" highlighted` ),
}
);
Extras
AutoComplete comes with several public methods and events that allow to go a step beyond depending of your needs. In the following examples, we will change the default behaviour of a search.
Multiple values
source
option allows to control the searched suggestions from the input value. So, if we split the value
argument passed in source
function and pass it to response()
method, it will automatically make a new search from last splitted value.
In this example, we use internal method response( value, suggestions )
, that accepts as first argument the searched value
and as second argument the suggestions
in which to search.
In source
function (and all events), instance context is binded (this
). So, you should not use arrow function if you want to keep instance context.
new AutoComplete(
input,
{
source: function( value ) {
this.values = value.trim().split( /s*,s*/ );
// We use internal method instead of source callback.
this.response( this.values.pop(), source );
},
onSelect: function( { label } ) {
this.values.push( label );
input.value = `${ this.values.filter( Boolean ).join( ', ' ) }, `;
},
}
);
Dynamic values
In this example, the source
is dynamic and it passes in response
callback suggestion based on user input (value
). We also render the suggestion as shown in renderItem
(@see example)
const colorSwatch = document.createElement( 'span' );
new AutoComplete(
input,
{
source: ( value, response ) => {
const isHex = /^#([0-9A-F]{3}){1,2}$/i.test( value );
response( isHex ? [ value ] : [] );
},
renderItem: ( suggestion, item ) => {
item.style.setProperty( '--color', suggestion.value );
item.append( colorSwatch.cloneNode() );
return suggestion.content;
},
}
);