so it can be styled in CSS
replicates all autocomplete functionality in JavaScript
I’ve enhanced it further and the code is available on GitHub. To use it, load the script anywhere in your HTML page as an ES6 module. The jsDelivr CDN URL can be used:
<span><span><span><datalist</span> id<span>="countrydata"</span>></span>
</span> <span><span><span><option</span>></span>Afghanistan<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Åland Islands<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Albania<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Algeria<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>American Samoa<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Andorra<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Angola<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Anguilla<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Antarctica<span><span></option</span>></span>
</span> ...etc...
<span><span><span></datalist</span>></span>
</span>
Or you can install it with npm if you’re using a bundler:
<span><span><span><label</span> for<span>="country"</span>></span>country<span><span></label</span>></span>
</span>
<span><span><span><input</span> type<span>="text"</span>
</span></span><span> <span>list<span>="countrydata"</span>
</span></span><span> <span>id<span>="country"</span> name<span>="country"</span>
</span></span><span> <span>size<span>="50"</span>
</span></span><span> <span>autocomplete<span>="off"</span> /></span>
</span>
Your elements must use the value format. For example:
<span><span><span><datalist</span> id<span>="mylist"</span>></span>
</span> <span><span><span><option</span>></span>label one<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>label two<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>label three<span><span></option</span>></span>
</span><span><span><span></datalist</span>></span>
</span>
Note: can’t be used, since it results in an empty element that can’t be styled!
CSS can then be added to style some or all and elements. For example:
<span><span><span><datalist</span> id<span>="mylist"</span>></span>
</span> <span><span><span><option</span> value<span>="label one"</span> /></span>
</span> <span><span><span><option</span> value<span>="label two"</span> /></span>
</span> <span><span><span><option</span> value<span>="label three"</span> /></span>
</span><span><span><span></datalist</span>></span>
</span>
Example:
See the Pen HTML5 autocomplete CSS styling by SitePoint (@SitePoint) on CodePen.
Styling works, but is it worth the effort? I suspect not …
Re-implementing the browser’s standard keyboard, mouse, and touch controls with reasonable accessibility is difficult. The MDN example doesn’t support keyboard events and, while I tried to improve it, there will inevitably be issues on some devices.
You’re relying on 200 lines of JavaScript to solve a CSS problem. It minifies to 1.5kB, but could introduce performance issues if you required many long elements on the same page.
If JavaScript is a requirement, would it be preferable to use a prettier, more consistent, battle-tested JavaScript component?
The control falls back to a standard HTML5 without styling when JavaScript fails, but that’s a minor benefit.
Creating an Ajax-enhanced
Presuming your designer is happy to accept browser styling differences, it’s possible to enhance standard functionality using JavaScript. For example:
Implement optional validation which only accepts a known value in the .
Set elements from data returned by Ajax calls to search APIs.
Set other field values when an option is chosen. For example, selecting “United States of America” sets “US” in a hidden input.
The code primarily needs to redefine elements, although there are several coding considerations:
An Ajax API request should only occur once a minimum number of characters has been entered.
Typing events should be debounced . That is, an Ajax call is only triggered once the user has stopped typing for at least half a second.
Query results should be cached so it’s not necessary to repeat or parse identical calls.
Unnecessary queries should be avoided. For example, entering “un” returns 12 countries. There’s no need to make further Ajax calls for “unit” or “united” because all the resulting options are contained in the original 12 results.
I’ve created a standard Web Component for this, and the code is available on GitHub. The CodePen example below allows you to select a valid country after entering at least two characters. A music artist autocomplete then returns artists who originated in that country with names matching the search string:
See the Pen HTML5 with Ajax autocomplete by SitePoint (@SitePoint) on CodePen.
The country look-up API is provided by restcountries.eu.
The music artist look-up API is provided by musicbrainz.org.
To use it in your own application, load the script anywhere in your HTML page as an ES6 module. The jsDelivr CDN URL can be used:
<span><span><span><datalist</span> id<span>="countrydata"</span>></span>
</span> <span><span><span><option</span>></span>Afghanistan<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Åland Islands<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Albania<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Algeria<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>American Samoa<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Andorra<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Angola<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Anguilla<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Antarctica<span><span></option</span>></span>
</span> ...etc...
<span><span><span></datalist</span>></span>
</span>
Or you can install it with npm if you’re using a bundler:
<span><span><span><label</span> for<span>="country"</span>></span>country<span><span></label</span>></span>
</span>
<span><span><span><input</span> type<span>="text"</span>
</span></span><span> <span>list<span>="countrydata"</span>
</span></span><span> <span>id<span>="country"</span> name<span>="country"</span>
</span></span><span> <span>size<span>="50"</span>
</span></span><span> <span>autocomplete<span>="off"</span> /></span>
</span>
Create an element with a child to use as the data-entry field. For example, the country lookup uses this:
<span><span><span><datalist</span> id<span>="mylist"</span>></span>
</span> <span><span><span><option</span>></span>label one<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>label two<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>label three<span><span></option</span>></span>
</span><span><span><span></datalist</span>></span>
</span>
element attributes:
attribute
description
api
the REST API URL (required)
resultdata
the name of the property containing a result array of objects in the returned API JSON (not required if only results are returned)
resultname
the name of the property in each result object which matches the search input and is used for datalist
elements (required)
querymin
the minimum number of characters to enter before a search is triggered (default: 1)
inputdelay
the minimum time to wait in milliseconds between keypresses before a search occurs (default debounce: 300)
optionmax
the maximum number of autocomplete options to show (default: 20)
valid
if set, this error message is shown when an invalid value is selected
The REST URL must contain at least one ${id} identifier, which is substituted by the value set in the with that id. In the example above, ${country} in the api URL references the value in the child , which has an id of "country". The URL will normally use the child input, but any other fields on the page can be referenced.
The restcountries.eu API returns a single object or array of objects containing country data. For example:
<span><span><span><datalist</span> id<span>="countrydata"</span>></span>
</span> <span><span><span><option</span>></span>Afghanistan<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Åland Islands<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Albania<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Algeria<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>American Samoa<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Andorra<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Angola<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Anguilla<span><span></option</span>></span>
</span> <span><span><span><option</span>></span>Antarctica<span><span></option</span>></span>
</span> ...etc...
<span><span><span></datalist</span>></span>
</span>
The resultdata attribute doesn’t need to be set because this is the only data returned (there’s no wrapper object). The resultname attribute must be set to "name" because that property is used to populate datalist elements.
Other fields can be auto-filled when an option is chosen. The following inputs receive the "alpha2Code" and "region" property data because a data-autofill attribute has been set:
<span><span><span><label</span> for<span>="country"</span>></span>country<span><span></label</span>></span>
</span>
<span><span><span><input</span> type<span>="text"</span>
</span></span><span> <span>list<span>="countrydata"</span>
</span></span><span> <span>id<span>="country"</span> name<span>="country"</span>
</span></span><span> <span>size<span>="50"</span>
</span></span><span> <span>autocomplete<span>="off"</span> /></span>
</span>
How datalist-ajax works
You can skip this section if you’d rather not read 230 lines of code and keep the magic alive!
The code initially creates a new within the , which it attaches to the child using a list attribute. An input event handler monitors the and calls a runQuery() function when a minimum number of characters have been entered and the user is not still typing.
runQuery() builds the API URL from data in the form and makes an Ajax call using the Fetch API. The returned JSON is parsed, then a reusable DOM fragment containing elements is constructed and placed into a cache.
A datalistUpdate() function is called, which updates the with the appropriate cached DOM fragment. Further calls to runQuery() avoid Ajax calls if a query has already been cached or a previous query can be used.
A change event handler also monitors the , which is triggered when focus is moved from the field and the value has been modified. The function checks that the value matches a known option and, if necessary, uses the Constraint Validation API to show the error message provided in the valid attribute.
Assuming a valid option has been chosen, the change handler function populates all fields with matching data-autofill attributes. A reference to the auto-fill fields is retained so they can be reset if an invalid option is subsequently entered.
Note that the shadow DOM is not used. This ensures the auto-complete (and ) elements can be styled by CSS and accessed by other scripts if necessary.
Dunkin’
The HTML5 has limitations but is ideal if you require a simple framework-agnostic auto-complete field. The lack of CSS support is a shame, but browser vendors may eventually address that oversight.
Any of the code and examples shown in this tutorial can be adopted for your own projects.
FAQs About Lightweight Autocomplete Controls with the HTML5 Datalist
What is the HTML5 datalist element and how does it work? The HTML5 datalist element is a pre-defined list of options for an input element. It provides an “autocomplete” feature on form elements. The datalist element uses the id attribute to associate it with a specific input element. The input element uses the list attribute to identify the datalist. Inside the datalist, you can define option elements that represent the available options for the input field.
How can I use the HTML5 datalist for autocomplete? To use the HTML5 datalist for autocomplete, you need to associate the datalist with an input field. This is done by adding the list attribute to the input field and setting its value to the id of the datalist. The browser will then suggest autocomplete options based on the user’s input and the defined options in the datalist.
Can I use the HTML5 datalist element in all browsers? The HTML5 datalist element is supported in most modern browsers, including Chrome, Firefox, Safari, and Edge. However, it’s not supported in Internet Explorer 9 and earlier versions. You can check the current browser compatibility on websites like Can I Use.
How can I style the HTML5 datalist options? Unfortunately, the styling options for the HTML5 datalist element are quite limited. The appearance of the dropdown list is controlled by the browser and can’t be easily customized with CSS. However, you can style the input field associated with the datalist.
Can I use multiple datalists for a single input field? No, you can’t associate multiple datalists with a single input field. The list attribute of the input field can only take one id, which corresponds to one datalist. If you need to provide multiple sets of options, you might need to use JavaScript to dynamically change the options based on user input.
Can I use the HTML5 datalist with other input types? Yes, the HTML5 datalist can be used with various input types, including text, search, url, tel, email, date, month, week, time, datetime-local, number, range, and color. However, the autocomplete feature might not work as expected with some input types like range or color.
Can I use the HTML5 datalist with a select element? No, the HTML5 datalist can’t be used with a select element. The datalist is designed to provide autocomplete suggestions for an input field, while the select element provides a dropdown list of options. If you need a dropdown list, you should use the select element instead.
Can I use JavaScript with the HTML5 datalist? Yes, you can use JavaScript with the HTML5 datalist to dynamically add, remove, or change options. However, keep in mind that the datalist doesn’t support events like onchange or onclick on its options. You need to add the event listeners to the associated input field instead.
Can I use the HTML5 datalist for a search field? Yes, the HTML5 datalist can be a great choice for a search field. It can provide autocomplete suggestions based on the user’s input, which can enhance the user experience. However, you need to manually populate the datalist with the possible search terms.
Can I use the HTML5 datalist with a textarea? No, the HTML5 datalist can’t be used with a textarea. The datalist is designed to provide autocomplete suggestions for an input field, not for a textarea. If you need autocomplete functionality for a textarea, you might need to use a JavaScript library or build your own solution.