Autocomplete Javascript library

A small Javascript library to integrate international address autocompletion into any HTML form.

Try it out in the autocomplete example form.

Changelog

Version 1.4.0 12-10-2023
  • Add autoSelectSingleAddress option to automatically select an address match if it's the only menu item. Enabled by default but won't have any effect unless the autoFocus option is also enabled.
  • Option autoFocus is now enabled by default.
  • Restore menu item focus on mouseout and when opening the menu.
Version 1.3.3 30-08-2023
  • Add search method option to keep the menu closed.
  • Search method options can now be specified via options object.
  • Implement context update via newContext property in autocomplete response.
Version 1.3.2 21-12-2022
  • Generate a session identifier for each input element.
Version 1.3.1 28-09-2022
  • Custom events now bubble up through the DOM tree.
  • Add an optional context parameter to the search() method.
Version 1.3.0 05-01-2022
  • Show results instantly for values of 1-3 characters.
  • Increase pixel density of loader gif image to look better on high DPI displays.
  • Initialize context in lowercase.
  • Add publicly accessible version property.
  • Don't change existing autocomplete attribute.
  • Support inline scrolling in autocomplete menu.
  • Use relative units (em) to scale with font-size.
Version 1.2.3 03-05-2021
  • Use the same classname for multiple live regions. Fixes live region text displayed on page.
Version 1.2.2 18-03-2021
  • Removed autoSelect option because it can cause users to unknowingly select the wrong address.
Version 1.2.1 16-03-2021
  • Fixed undefined defaults property.
  • Prevent making multiple autocomplete requests.
  • Add XHR error handling to getDetails().
  • Add loading class to input element when calling getDetails().
  • Pass more ESLint tests.
Version 1.2 02-03-2021
  • Support for Asynchronous Module Definition (AMD).
  • Select menu items using mousemove instead of mouseover to prevent newly created items under the mouse cursor from receiving focus while the mouse hasn't moved.
  • Menu and live region elements are now accessible as properties of an autocomplete instance (autocomplete.menu, autocomplete.menuItems, autocomplete.liveRegion).
  • Allow submit on Enter key if the menu is open but no item has focus. It would otherwise require pressing Enter twice to submit a form or trigger form validation.
  • Remove menu item focus when the input value has changed to fix potentially selecting an old menu item if autoFocus/autoSelect is enabled.
  • Fixed keeping incorrect previous value/context below minLength.
  • Added language support via language option and setLanguage method.
  • Add legacy values for up/down keys to support IE11.
  • Make menu resizing optional.
  • Make focused item data available via Event detail property.
  • Various small tweaks and bugfixes.
Version 1.1 18-12-2019
  • Added reset() method.
  • Added destroy() method.
  • Trigger autocomplete-create event when creating an autocomplete instance.
  • Reset autocomplete context when input is below minimum length.
  • Fixed XMLHttpRequest error handling.
  • Fixed IE11 compatibility issues.
Version 1.0 10-09-2019
Initial release.

Read more

Example implementation

The following example code can be used as a starting point for your implementation.

HTML

<form>
	<input type="text" class="input-autocomplete" placeholder="City, street or postcode">
</form>

Javascript

const inputElement = document.querySelector('.input-autocomplete'),
	autocomplete = new PostcodeNl.AutocompleteAddress(inputElement, {
		autocompleteUrl: 'https://your-proxy-script-autocomplete-url', // Required
		addressDetailsUrl: 'https://your-proxy-script-details-url', // Required
		// Specify more options here...
	});

inputElement.addEventListener('autocomplete-select', function (e) {
	console.log('Selected item:', e.detail);
});

Address selection

When a full address is selected from the autocomplete menu, call the getDetails method and use the result to populate form fields and show the address. Example:

HTML

<form class="autocomplete-example-form">
	<input type="text" class="input-autocomplete" placeholder="City, street or postcode">
	<input type="hidden" name="country">
	<input type="hidden" name="locality">
	<input type="hidden" name="postcode">
	<input type="hidden" name="street">
	<input type="hidden" name="building">
</form>

<address class="autocomplete-result"></address>

Javascript

const inputElement = document.querySelector('.input-autocomplete'),
	resultElement = document.querySelector('.autocomplete-result'),
	form = document.querySelector('.autocomplete-example-form'),
	autocomplete = new PostcodeNl.AutocompleteAddress(inputElement, {
		// Options
	});

inputElement.addEventListener('autocomplete-select', function (e) {
	if (e.detail.precision === 'Address')
	{
		autocomplete.getDetails(e.detail.context, function (result) {
			const fields = ['country', 'locality', 'postcode', 'street', 'building'];

			for (let i = 0, field; field = fields[i++];)
			{
				form.elements[field].value = result.address[field];
			}

			if (typeof result.mailLines !== 'undefined')
			{
				// Show the address.
				resultElement.innerHTML = result.mailLines.join('<br>');
			}
		});
	}
});

Setting defaults

The default value of each option can be set via the defaults object. Any autocomplete instance will then use the new default value.

Javascript

// Set default URL values:
PostcodeNl.AutocompleteAddress.defaults.autocompleteUrl = 'https://autocomplete-url';
PostcodeNl.AutocompleteAddress.defaults.addressDetailsUrl = 'https://details-url';

Options

context: string
Initial autocomplete context. E.g. a country code "nld", "bel" or "deu" to start searching in that country. Default: "nld"
autocompleteUrl: string
URL that will return autocomplete JSON data. Default: undefined
addressDetailsUrl: string
URL that will return address details JSON data. Default: undefined
tags: Object
Text to use with tags. Default:
{
	'unvalidated-housenumber': '(unknown house number)',
	'unvalidated-housenumber-addition': '(unknown house number addition)',
}
cssPrefix: string
Prefix for CSS classnames. Default: "postcodenl-autocomplete-"
minLength: number
Minimum number of characters typed before a search is performed. Default: 1
delay: number
Delay in milliseconds between when a keystroke occurs and when a search is performed. Not applied when input length is 1-3 characters in order to provide immediate feedback when a user starts typing. Default: 300
appendTo: string|HTMLElement
Which element the menu should be appended to. Default: document.body
autoFocus: boolean
Focus the first item when the menu is shown. Default: true
autoSelectSingleAddress: boolean
Automatically select an address match if it's the only menu item. Requires the autoFocus option to be enabled or won't have any effect. Default: true
autoResize: boolean
Automatically calculate menu width. Disable to define width in CSS. Default: true
getResponseMessage: Function
Get screen reader text for a successful response with at least one match. Override this function to translate the message. Default:
function (count, languageTag)
{
	let message;

	if (count > 1)
	{
		message = count + ' address suggestions available. ';
	}
	else
	{
		message = 'One address suggestion available. ';
	}

	message += 'Use up and down arrow keys to navigate.';

	return message;
}
language: string
The language used for API calls. If defined, is added to the request for autocomplete suggestions. Default: undefined

Properties

version: string
Holds the autocomplete library version string.

Example

PostcodeNl.AutocompleteAddress.version; // "1.4.0"

Methods

setCountry(iso3Code)

Set the country to start searching in.

iso3Code: string
ISO 3166-1 alpha-3 country code.

Trigger a search on the specified input element. If invoked without a term, the current input's value is used.

element: HTMLElement
Input element associated with the autocomplete instance.
term: string
Search query, optional.
context: string
Autocomplete context, optional.
options: Object
Autocomplete options object, optional. Use this in place of the term parameter to specify named options. All its properties are optional.
term: string
Search query.
context: string
Autocomplete context.
showMenu: boolean
Whether the menu should be shown. Set to false to perform a "hidden" search (useful with prefilled input values).

Example

// Perform a search without showing the menu:
autocompleteInstance.search(inputElement, { term: 'test', showMenu: false });
xhrGet(url, success) → {XMLHttpRequest}

Create an XMLHttpRequest GET request.

url: string
URL to which the request is sent.
success: Function
Function that is executed if the request succeeds.

Returns: XMLHttpRequest

Object representing the eventual completion/failure of the request, and its resulting value.
getSuggestions(context, term, response) → {XMLHttpRequest}

Get autocomplete matches for the specified context and term.

context: string
A place identifier denoting the context to search in. e.g. “nld”.
term: string
The search query to process. e.g. “2012ES”, “Haarlem”, “Julian”.
response: Function
Function that handles the response.

Returns: XMLHttpRequest

Object representing the eventual completion/failure of the request, and its resulting value.
getDetails(addressId, [dispatchCountry], response) → {XMLHttpRequest}

Get address details for the specified address identifier.

addressId: string
Address identifier returned by a match of precision “Address”.
dispatchCountry (optional): string
Dispatching country ISO3 code, used to determine country address line presence and language. If not given, country is not added in mailLines.
response: Function
Function that handles the response.

Returns: XMLHttpRequest

Object representing the eventual completion/failure of the request, and its resulting value.
renderItem(ul, item) → {HTMLElement}

Method that controls the creation of each menu item.

ul: HTMLElement
Element that the newly created list item must be appended to.
item: Object
Single autocomplete item.

Returns: HTMLElement

List item element containing an autocomplete match.
highlight(str, indices) → {string}

Highlight matched portions in the item label.

str: string
Item label to highlight.
indices: Array.Array.<number>
Array of character offset pairs.

Returns: string

Highlighted string (using <mark> elements).
announce(str)

Announce screen reader text via the live region.

str: string
Text to announce.
destroy()

Removes autocomplete functionality from associated input elements.

reset()

Reset to initial context, clear the menu, clear input values.

setLanguage(languageTag)

Set the language used for API calls.

languageTag: string
Language tag, e.g. "nl", "nl_NL", "en-GB" or "de-DE".

Events

autocomplete-create

Triggered when the autocomplete is created.

Example

inputElement.addEventListener('autocomplete-create', function () {});
const autocomplete = new PostcodeNl.AutocompleteAddress(inputElement, { /* Options */ });
// autocomplete-create event triggered.
autocomplete-open

Triggered when the menu is opened.

Example

inputElement.addEventListener('autocomplete-open', function () {});
autocomplete-close

Triggered when the menu is closed.

Example

inputElement.addEventListener('autocomplete-close', function () {});
autocomplete-focus

Triggered when focus is moved to an item by keyboard (not selecting). The default action is to replace the input element's value with the value of the focused item. Cancel this event to prevent updating the input element's value.

Example

inputElement.addEventListener('autocomplete-focus', function (e) {
	e.preventDefault(); // Event cancelled, input value won't be updated.
});
autocomplete-select

Triggered when an item is selected from the menu. Selected item data is available on the detail property of the Event object. Cancel this event to prevent updating the input element's value.

Example

inputElement.addEventListener('autocomplete-select', function (e) {
	console.log('Selected item:', e.detail);
	e.preventDefault(); // Event cancelled, input value won't be updated.
});

Triggered before a search is performed. Cancel this event to prevent the request for address suggestions.

Example

inputElement.addEventListener('autocomplete-search', function (e) {
	e.preventDefault(); // Event cancelled, no request made.
});
autocomplete-response

Triggered after a search completes, before the menu is shown. Result data is available via the detail property of the Event object. Cancel this event to prevent rendering address suggestions.

Example

inputElement.addEventListener('autocomplete-response', function (e) {
	console.log('Address suggestions:', e.detail.matches);
	e.preventDefault(); // Event cancelled, no items added to the menu.
});
autocomplete-error

Triggered when the request for autocomplete suggestions fails.

Example

inputElement.addEventListener('autocomplete-error', function (e) {
	console.log('ProgressEvent:', e.detail.event);
	console.log('XMLHttpRequest:', e.detail.request);
});