Categories: CSSScriptWeb Design

Lightweight JS Autocomplete & Autosuggest: Ajax & Local Data – Ajax Autocomplete Vanilla

Ajax Autocomplete is a vanilla JavaScript library that enables autocomplete and autosuggest functionality on any standard text input.

It supports both local array data and remote Ajax or JSONP endpoints, selectable per instance.

Features:

  • Pure ES6+ vanilla JavaScript.
  • Built-in response caching to reduce redundant network requests on repeated queries.
  • Bad-query prevention that tracks zero-result root queries and skips future requests with the same prefix.
  • Allows you to control how many characters the user must type before suggestions appear.
  • Keyboard navigation with arrow keys, Enter to confirm, Escape to dismiss, and Tab support with optional cursor retention.
  • Inline hint display for first-match type-ahead prediction.
  • Flexible container positioning: auto, top, or bottom orientation with scroll-aware recalculation on window resize.
  • Comma-separated or multi-token input fields that suggest values for each token.

Use Cases:

  • Country selection dropdown for checkout forms.
  • Dynamic site search bar that fetches product names from a database.
  • Tag input field that suggests available categories as the user types.
  • User lookup tool in an admin dashboard that queries an external API.

How to use it:

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;
}

Alternatives:

FAQs:

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.

rssfeeds-admin

Share
Published by
rssfeeds-admin

Recent Posts

Why Investors Are Betting Billions On Low Earth Orbit Satellites

The post Why Investors Are Betting Billions On Low Earth Orbit Satellites appeared first on…

15 minutes ago

Advanced Systems Group Names Kevin Poole Senior Project & Support Manager For Workflow & Tools Practice

Kevin Poole Advanced Systems Group, a technology and services provider for media creatives and content…

15 minutes ago

NAB Show: Utah Scientific To Showcase Hybrid SDI/IP Innovations

Utah Scientific said it will spotlight its expanding portfolio of hybrid SDI/IP routing, conversion, control…

15 minutes ago

NAB Show: Miri To Introduce V410 Live 4K Encoder/Decoder

Miri Technologies’ V410 live 4K encoder/decoder will make its North American debut at the NAB…

16 minutes ago

NAB Show: Net Insight Unveiling JPEG XS For Live IP Media Production

Net Insight is introducing a full IP JPEG XS solution at NAB Show in Las…

16 minutes ago

NAB Show: FOR-A To Showcase Software-Defined, AI-Powered Workflows At NAB 2026

FOR-A Corp., will showcase its latest software-defined, AI-powered workflow at NAB Show in Las Vegas,…

16 minutes ago

This website uses cookies.