layout | title |
---|---|
page-layout.njk |
plete |
A vanilla js autocomplete component that supports remote filtering.
It enhances an existing <input type="text"/>
element and provides callbacks when busy, ready and selections are made.
{% include examples/big-demo.html %}
There are more demos below
- Good WAI-ARIA support
- Supports multiple input types: keyboard, mouse, touch
- Supports local and remote filtering (async function as datasource)
- Custom rendering of elements
- 100% test coverage
- BSD-3 License
- Zero dependencies
This project is aiming for wide compatibility in modern, evergreen browsers.
Specifically, defaults, not safari <= 10, not ie <= 11, not IE_Mob <= 11
.
If you need to support legacy browsers in your project, you likely already have a transpiling setup and know how to use polyfills.
You can load plete
straight from jsDelivr or install it locally via npm
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/plete@0.3.x/dist/plete.css" />
<!-- this loads script with a global Plete constructor, CJS and ESM versions exist in dist/-->
<script src="https://cdn.jsdelivr.net/npm/plete@0.3.x/dist/plete.js"></script>
npm install plete --save
The dist/
folder contains all stylesheet and scripts, which you can include in your project.
<label>
Country
<!-- the input element to listen to events on -->
<input type="text" name="country" />
</label>
const plete = new Plete({
// the input element to listen to events on
input: document.querySelector("input[name='country']"),
// an array of strings/objects or an async function
dataSrc: [
{ id: "BEL", label: "Belgium" },
{ id: "DNK", label: "Denmark" },
{ id: "GER", label: "Germany" },
{ id: "MCO", label: "Monaco" },
{ id: "SRB", label: "Serbia" },
{ id: "ESP", label: "Spain" },
{ id: "SWE", label: "Sweden" },
{ id: "GBR", label: "United Kingdom" },
{ id: "USA", label: "United States of America" }
],
// a callback to receive the chosen value
select: function countrySelected(value) {
console.log(`The user selected: ${value}`);
}
});
The <input>
element to listen for events on
An array or async function with values to use as options.
Providing an array of string values as dataSrc
is only included for demo/prototyping purposes.
If you only need string values, you should consider using the <datalist>
element instead of plete
.
const dataSrc = ["Denmark", "Germany", "Spain", "Sweden", "United Kingdom"];
When providing an array of objects, they should have the following properties:
property | description |
---|---|
id |
A string that identifies the chosen value |
label |
A string to render to represent the value when rendered as an option |
const dataSrc = [
{ id: "BEL", label: "Belgium" },
{ id: "DNK", label: "Denmark" },
{ id: "GER", label: "Germany" },
{ id: "MCO", label: "Monaco" },
{ id: "SRB", label: "Serbia" },
{ id: "ESP", label: "Spain" },
{ id: "SWE", label: "Sweden" },
{ id: "GBR", label: "United Kingdom" },
{ id: "USA", label: "United States of America" }
];
Extra properties are allowed, and can be used for custom rendering of options.
Using an async function as dataSrc
allows us to do remote filtering and mapping the returned data into the format that plete
understands (see section on objects above).
const dataSrc = async function filterCountries(query) {
const response = await fetch(`https://restcountries.eu/rest/v2/name/${query}`);
if (!response.ok) {
return [];
}
const result = await response.json();
if (!Array.isArray(result)) {
return [];
}
return result.map(function(v) {
return {
id: v.alpha3Code,
label: v.name
}
});
}
A callback to call with the id
property of the selected value.
When dataSrc
is an array of strings, this will be the chosen string.
function countrySelected(value) {
console.log(`The user selected: ${value}`);
}
When set, the first suggestion will be automatically highlighted.
Default: true
A callback to call before filtering.
One or more CSS classes to add to the containing <plete-list>
element
The number of suggestions to display.
Default: 5
A callback to call after filtering.
The number of characters required before searching (when using remote).
Default: 3
A callback to render individual values.
This can be used for enriching the rendering of individual values.
render: function renderOption(item) {
return `<b>${item.id}</b> ${item.label}`;
}
The dataSrc
option can be an array of string values.
const dataSrc = ["Denmark", "Germany", "Spain", "Sweden", "United Kingdom"];
{% include examples/string-values.html %}
const dataSrc = [
{ id: "BEL", label: "Belgium" },
{ id: "DNK", label: "Denmark" },
{ id: "GER", label: "Germany" },
{ id: "MCO", label: "Monaco" },
{ id: "SRB", label: "Serbia" },
{ id: "ESP", label: "Spain" },
{ id: "SWE", label: "Sweden" },
{ id: "GBR", label: "United Kingdom" },
{ id: "USA", label: "United States of America" }
];
{% include examples/object-values.html %}
const dataSrc = async function filterCountries(query) {
const response = await fetch(`https://restcountries.eu/rest/v2/name/${query}`);
if (!response.ok) {
return [];
}
const result = await response.json();
if (!Array.isArray(result)) {
return [];
}
return result.map(function(v) {
return {
id: v.alpha3Code,
label: v.name
}
});
}
{% include examples/remote-filtering.html %}
{% include examples/custom-rendering.html %}
When plete
is initialized the DOM is updated. The passed <input>
element is wrapped in a <plete>
element. This element is an invisible inline element, which provides the container necessary for WAI-ARIA support (see WAI-ARIA Authoring Practices combobox section).
You can customize the rendering by overriding styles for <plete>, <plete-list>, <plete-item>
elements.
When the suggestions are visible, the DOM looks like this (with additional ARIA attrbutes).
<plete>
<input type="text" name="country" autocomplete="off" />
<plete-list>
<plete-item value="BEL">Belgium</plete-item>
<plete-item value="DNK">Denmark</plete-item>
<!-- ... --->
</plete-list>
</plete>
In order to avoid collisions with browser built-in autocomplete, it is recommended to use autocomplete="off"
on the <input>
element that is used with plete
.
<input type="text" name="country" autocomplete="off" />