Lightweight JS Autocomplete & Autosuggest: Ajax & Local Data – Ajax Autocomplete Vanilla
It supports both local array data and remote Ajax or JSONP endpoints, selectable per instance.
1. Download the library and load the following files in the document.
<!-- Core JavaScript Library --> <script src="autocomplete.js"></script> <!-- Optional. You can write your own CSS styles --> <link rel="stylesheet" href="autocomplete.css" />
2. Create a standard text input in the HTML.
<input type="text" id="location-input" placeholder="Type a city name..." autocomplete="off" />
3. Define your suggestion dataset as an array of { value, data } objects.
var cities = [
{ value: 'New York', data: 'NY' },
{ value: 'Los Angeles', data: 'CA' },
{ value: 'Chicago', data: 'IL' },
{ value: 'Houston', data: 'TX' },
{ value: 'Philadelphia', data: 'PA' }
]; 4. Attach autocomplete to the input using the local array
new Autocomplete(document.getElementById('location-input'), {
lookup: cities,
minChars: 1,
autoSelectFirst: true,
onSelect: function (suggestion) {
// suggestion.value holds the display text
// suggestion.data holds your metadata (state code here)
console.log('City: ' + suggestion.value + ' | Code: ' + suggestion.data);
}
}); 5. The library also works with plain string arrays.
var tags = ['JavaScript', 'TypeScript', 'CSS', 'HTML', 'WebAssembly'];
new Autocomplete(document.getElementById('location-input'), {
lookup: tags,
onSelect: function (suggestion) {
console.log('Tag selected: ' + suggestion.value);
}
}); 6. Fetch suggestions from a server endpoint as the user types:
new Autocomplete(document.getElementById('location-input'), {
serviceUrl: '/api/cities/suggest',
paramName: 'q',
dataType: 'json',
deferRequestBy: 250,
minChars: 2,
onSelect: function (suggestion) {
document.getElementById('location-input').value = suggestion.value;
console.log('Selected city code: ' + suggestion.data);
},
onSearchError: function (query, response, status, error) {
console.error('Suggestion request failed for: "' + query + '"', error);
}
}); Your server must return JSON in this format:
{
"query": "Chi",
"suggestions": [
{ "value": "Chicago", "data": "IL" },
{ "value": "Chico", "data": "CA" },
{ "value": "Chicopee", "data": "MA" }
]
} 7. Use the Custom Lookup Function when your data source requires custom logic. For example, filtering an in-memory index, combining multiple endpoints, or wrapping a third-party SDK.
new Autocomplete(document.getElementById('location-input'), {
lookup: function (query, done) {
// Run any async operation here, then call done() with the results object
fetch('/api/locations?term=' + encodeURIComponent(query))
.then(function (res) { return res.json(); })
.then(function (data) {
done({
suggestions: data.results.map(function (item) {
return { value: item.displayName, data: item.locationId };
})
});
})
.catch(function () {
done({ suggestions: [] }); // Return empty on error to avoid a broken state
});
},
onSelect: function (suggestion) {
console.log('Location ID: ' + suggestion.data);
}
}); 8. The library also has native JSONP support for working with cross-domain APIs that do not support CORS.
new Autocomplete(document.getElementById('location-input'), {
serviceUrl: 'https://partner-api.example.com/cities/search',
dataType: 'jsonp', // Triggers script-tag injection
jsonpCallbackParam: 'cb', // The callback parameter the API expects
jsonpTimeout: 6000, // Fire onSearchError if no response in 6 seconds
onSelect: function (suggestion) {
console.log('Received: ' + suggestion.value);
},
onSearchError: function (query, res, status, error) {
console.warn('JSONP timeout or error for query: ' + query);
}
}); 9. Set groupBy to a property name on the suggestion’s data object. The library groups all suggestions that share the same value for that property under a single labeled header.
var sports = [
{ value: 'Brooklyn Nets', data: { league: 'NBA', arena: 'Barclays Center' } },
{ value: 'New York Knicks', data: { league: 'NBA', arena: 'Madison Square Garden' } },
{ value: 'New York Giants', data: { league: 'NFL', arena: 'MetLife Stadium' } },
{ value: 'New York Rangers', data: { league: 'NHL', arena: 'Madison Square Garden' } }
]; new Autocomplete(document.getElementById('location-input'), {
lookup: sports,
groupBy: 'league', // Group rows by the 'league' property in the data object
formatGroup: function (suggestion, category) {
// Customize the group header HTML
return '<div class="autocomplete-group"><strong>' + category + '</strong></div>';
},
onSelect: function (suggestion) {
console.log(suggestion.value + ' plays at ' + suggestion.data.arena);
}
}); 10. Use paramName and transformResult together if your API uses a different query parameter name or returns data in a proprietary format.
new Autocomplete(document.getElementById('location-input'), {
serviceUrl: '/api/legacy/locations',
paramName: 'searchTerm', // Override the default 'query' parameter name
transformResult: function (response) {
// Parse the raw response and map it to the { suggestions: [] } format
var parsed = typeof response === 'string' ? JSON.parse(response) : response;
return {
suggestions: parsed.locations.map(function (loc) {
return { value: loc.cityName, data: loc.cityCode };
})
};
},
onSelect: function (suggestion) {
console.log('Code: ' + suggestion.data + ' | Name: ' + suggestion.value);
}
}); 11. Create delimiter-Based token input:
new Autocomplete(document.getElementById('location-input'), {
lookup: cities,
delimiter: ',',
onSelect: function (suggestion) {
// The library appends the selected value to the existing tokens automatically
console.log('Added token: ' + suggestion.value);
}
}); 12. All configuration options and callback functions:
noCache (Boolean): Disables response caching when set to true. Default: false.delimiter (String | RegExp): Splits the input value on this separator and uses the last segment as the active query. Default: none.minChars (Number): Minimum character count the user must type before the suggestion lookup fires. Default: 1.triggerSelectOnValidInput (Boolean): Fires the select event automatically when the input value is an exact, case-insensitive match for a single suggestion. Default: true.preventBadQueries (Boolean): Tracks zero-result queries and blocks future requests for any query that starts with the same root string. Default: true.autoSelectFirst (Boolean): Pre-highlights the first suggestion in the list on display. Default: false.beforeRender (Function): function(container, suggestions) {} — called before the suggestion container becomes visible. Use it to manipulate the container DOM. container is the raw DOM element.formatResult (Function): function(suggestion, currentValue) {} — custom rendering function for each suggestion row. Returns an HTML string.formatGroup (Function): function(suggestion, category) {} — custom rendering function for a group header row. Returns an HTML string.groupBy (String): A property name on the suggestion data object. Suggestions that share the same value for this property render under a single labeled header.maxHeight (Number): Maximum height of the suggestion container in pixels. Default: 300.width (Number | String): Suggestion container width. Pass a number for a fixed pixel width, 'flex' to match the widest suggestion, or 'auto' to match the input element width. Default: 'auto'.zIndex (Number): CSS z-index applied to the suggestion container. Default: 9999.appendTo (String | HTMLElement): The DOM element where the suggestion container appends. Accepts a CSS selector string or an HTML element reference. The target element must have position: absolute or position: relative set. Default: document.body.forceFixPosition (Boolean): Forces automatic position recalculation when appendTo targets an element other than document.body. Default: false.orientation (String): Vertical display direction for the suggestion container. Accepts 'auto', 'top', or 'bottom'. The 'auto' value places the container on whichever side has more viewport space. Default: 'bottom'.preserveInput (Boolean): Keeps the raw input value unchanged while the user navigates suggestions with arrow keys. Default: false.showNoSuggestionNotice (Boolean): Renders a notice inside the suggestion container when a query returns zero results. Default: false.noSuggestionNotice (String | HTMLString | Element): Content for the no-results label. Accepts a plain string, an HTML string, or a DOM element. Default: 'No results'.onInvalidateSelection (Function): function() {} — called when the user modifies the input value after a suggestion was selected. this refers to the input element.tabDisabled (Boolean): When true, keeps the cursor in the input field after Tab selects a suggestion. Default: false.lookup (Array | Function): The local suggestion source. Pass an array of strings, an array of { value, data } objects, or a function(query, done) {} callback for custom async logic.lookupLimit (Number): Maximum number of local results the library displays. Default: no limit.lookupFilter (Function): function(suggestion, query, queryLowerCase) {} — custom filter function for local lookups. The default performs a case-insensitive partial string match against suggestion.value.serviceUrl (String | Function): The server endpoint URL, or a function that returns the URL string dynamically.type (String): HTTP method for the Ajax request. Default: 'GET'.dataType (String): Expected response format. Accepts 'text', 'json', or 'jsonp'. When 'jsonp' is set, the library injects a <script> tag. Default: 'text'.paramName (String): The query parameter key the library sends to the server. Default: 'query'.params (Object): Additional key-value pairs sent alongside the query on every request.deferRequestBy (Number): Milliseconds to wait after a keystroke before firing the Ajax request. Use this to debounce rapid typing. Default: 0.ajaxSettings (Object): Extra options passed to the native fetch() call. Accepts headers, credentials, mode, and cache. The library ignores this option for JSONP requests.ignoreParams (Boolean): When true, the library omits params from the request entirely. Default: false.jsonpCallbackParam (String): The JSONP callback parameter name the external API expects. Default: 'callback'.jsonpTimeout (Number): Milliseconds before a pending JSONP request is considered timed out and onSearchError fires. Default: 10000.onSearchStart (Function): function(params) {} — called before each Ajax request. this refers to the input element.onHint (Function): function(hint) {} — called to populate the input with a type-ahead hint based on the first matching suggestion. this refers to the input element.onSearchComplete (Function): function(query, suggestions) {} — called after the Ajax response is processed. suggestions is the result array. this refers to the input element.transformResult (Function): function(response, originalQuery) {} — transforms the raw server response into the { suggestions: [] } format the library expects before caching or rendering.onSelect (Function): function(suggestion) {} — called when the user confirms a suggestion. this refers to the input element.onSearchError (Function): function(query, response, textStatus, error) {} — called when an Ajax or JSONP request fails. this refers to the input element.onHide (Function): function(container) {} — called just before the suggestion container hides. container is the raw DOM element.13. API methods.
// Retrieve a live instance from a DOM element reference
var ac = Autocomplete.getInstance(document.getElementById('location-input'));
// Update any option on a running instance without reconstructing it
ac.setOptions({ maxHeight: 400, deferRequestBy: 300 });
// Clear both the response cache and the current suggestion list
ac.clear();
// Clear only the cached responses; leave current suggestions in place
ac.clearCache();
// Temporarily suspend autocomplete behavior (useful during form validation)
ac.disable();
// Re-activate autocomplete after it was disabled
ac.enable();
// Programmatically close the suggestion container
ac.hide();
// Destroy the instance: detach all event listeners, remove the container from the DOM,
// and delete the entry from the internal WeakMap to free memory
ac.dispose();
// You can also chain initialization and a method call by saving the constructor return value:
// Create an instance and immediately call a method on it
var ac = new Autocomplete(document.getElementById('location-input'), { lookup: cities });
ac.setOptions({ autoSelectFirst: true }); 14. The library generates the following class names that you can customize your autocomplete dropdown using CSS styles.
<div class="autocomplete-suggestions"> <div class="autocomplete-group"><strong>NBA</strong></div> <div class="autocomplete-suggestion autocomplete-selected">Brooklyn Nets</div> <div class="autocomplete-suggestion">New York Knicks</div> </div>
/* Outer suggestion container */.autocomplete-suggestions {
border: 1px solid #ccc;
background: #fff;
overflow-y: auto;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
/* Each suggestion row */.autocomplete-suggestion {
padding: 8px 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer; /* Required for tap events on Mobile Safari */}
/* Currently highlighted row */.autocomplete-selected {
background: #eef2ff;
color: #3333cc;
}
/* Bolded matched characters injected by the default formatResult */.autocomplete-suggestions strong {
font-weight: 600;
color: #3366ff;
}
/* Group header row */.autocomplete-group {
padding: 4px 12px;
}
.autocomplete-group strong {
display: block;
border-bottom: 1px solid #e0e0e0;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #999;
} Q: Why does the suggestion container appear behind modals or fixed headers on my page?
A: The default zIndex is 9999. If your page contains elements with a higher stacking context, pass a higher value in the options: new Autocomplete(el, { zIndex: 10001 }).
Q: How do I connect this library to a REST API that uses a different parameter name and returns data in a custom schema?
A: Use paramName to set the query key the server expects, and use transformResult to remap the response body to { suggestions: [{ value, data }] }.
Q: The library fires too many Ajax requests when the user types quickly. How do I reduce the load?
A: Set deferRequestBy to a value between 150 and 300 milliseconds. The library debounces the request by that interval from the last keystroke.
Q: Can I attach different configurations to multiple input fields on the same page?
A: Yes. Each new Autocomplete() call creates an independent instance stored against that specific input element’s reference.
The post Lightweight JS Autocomplete & Autosuggest: Ajax & Local Data – Ajax Autocomplete Vanilla appeared first on CSS Script.
Crimson Desert has sold an impressive 3 million copies in just five days. Pearl Abyss’…
As players work their way through Crimson Desert, they’re discovering more and more unexpected things…
Nintendo has reportedly cut back on manufacturing Switch 2 consoles following weaker than expected holiday…
ABILENE, Texas (KTAB/KRBC) – A gas leak has closed part of Beltway South in south…
ABILENE, Texas (KTAB/KRBC) – A police presence was seen in north Abilene as officers investigate…
CALLAHAN COUNTY, Texas (KTAB/KRBC) - A fiery crash in Callahan County has left one person…
This website uses cookies.