Skip to Content


Run an AJAX autocomplete search using jQuery UI.

JavaScript February 11, 2021


nebula.autocompleteSearch(element, types)


(Required) (Object (or String)) The jQuery object (or selector) of the search input field
Default: None

(Optional) (String) A comma-separated string of post types to include
Default: 'any'

Request or provide clarification »


Include only posts and pages in search.

nebula.loadJS(, 'jquery-ui').then(function(){ //Ensure jQuery-UI JS is loaded
    jQuery('#example-input').on('keyup paste', function(){ //Add the listener
        nebula.autocompleteSearch(jQuery(this), 'post,page');

nebula.loadCSS(; //Load the jQuery-UI CSS too

Search all post types by simply using the WordPress core "s" class.

<input class="s" type="text" placeholder="Search this site..." />

Customize the post types in an HTML form without needing to re-write any JavaScript

<input class="search" type="text" data-types="post,page" />

Additional Notes

For an easier implementation, you could simply add the class s to the search input. See autocompleteSearchListeners().

On keypress or paste, this function triggers nebula_autocomplete_search_start.

On autocomplete success, nebula_autocomplete_search_success is triggered.

When search results are available, nebula_autocomplete_search_results is triggered, otherwise nebula_autocomplete_search_no_results is triggered if no results are available.

On AJAX error, this function triggers nebula_autocomplete_search_error.

Was this page helpful? Yes No

    A feedback message is required to submit this form.

    Please check that you have entered a valid email address.

    Enter your email address if you would like a response.

    Thank you for your feedback!

    Source File

    Located in /assets/js/modules/search.js on line 128.

    No Hooks

    This function does not have any filters or actions available. Request one?
    nebula.autocompleteSearch = function(element, types = ''){
        if ( typeof element === 'string' ){
            element = jQuery(element);
        if ( types && Array.isArray(types) ){
            types = types.join(','); //Convert an array to to a comma-separated string
        nebula.dom.document.trigger('nebula_autocomplete_search_start', element);
        nebula.timer('(Nebula) Autocomplete Search', 'start');
        nebula.timer('(Nebula) Autocomplete Response', 'start');
        if ( element.val().trim().length ){
            if ( element.val().trim().length >= 2 ){ //This checks the length for animation but the minlength (below) handles it for autocomplete
                //Add "searching" class for custom Nebula styled forms
                }, 10_000);
                //Swap magnifying glass on Bootstrap input-group
                element.closest('.input-group, .nebula-input-group').find('.fa-search').removeClass('fa-search').addClass('fa-spin fa-spinner');
            } else {
                element.closest('.input-group, .nebula-input-group').find('.fa-spin').removeClass('fa-spin fa-spinner').addClass('fa-search');
            let typesQuery = '';
            if ( types ){
                typesQuery = '&types=' + types;
            if ( typeof element.autocomplete !== 'function' ){
      'nebula.autocompleteSearch requires jQuery UI. Load that library before calling this function', '/functions/autocompletesearch/');
                return false;
            element.autocomplete({ //jQuery UI dependent
                position: {
                    my: 'left top-2px',
                    at: 'left bottom',
                    collision: 'flip',
                source: async function(request, sourceResponse){
                    let searchResults = nebula.memoize('get', 'autocomplete search (' + request.term.toLowerCase() + ') [' + typesQuery + ']'); //Try from stored memory first
                    if ( !searchResults ){
                        var fetchResponse = await fetch( + '/wp-json/nebula/v2/autocomplete_search?term=' + request.term + typesQuery, {importance: 'high'}).then(function(fetchResponse){
                            return fetchResponse.json();
                            searchResults = nebula.memoize('set', 'autocomplete search (' + request.term.toLowerCase() + ') [' + typesQuery + ']', fetchData); //Add to stored memory
                            nebula.dom.document.trigger('nebula_autocomplete_search_error', request.term);
                                ga('send', 'exception', {'exDescription': '(JS) Autocomplete AJAX error: ' + error, 'exFatal': false});
                                nebula.crm('event', 'Autocomplete Search AJAX Error');
                            }, 1500, 'autocomplete error buffer');
                            element.closest('.input-group, .nebula-input-group').find('.fa-spin').removeClass('fa-spin fa-spinner').addClass('fa-search');
                    nebula.dom.document.trigger('nebula_autocomplete_search_success', searchResults);
                    ga('set',, 1);
                    var noSearchResults = ' (No Results)'; //Prep the string
                    if ( searchResults ){
                        nebula.dom.document.trigger('nebula_autocomplete_search_results', searchResults);
                        jQuery.each(searchResults, function(index, value){
                            value.label = value.label.replaceAll(/&#038;/g, '\&');
                        noSearchResults = '';
                    } else {
                        let thisEvent = {
                            category: 'Internal Search',
                            action: 'Autocomplete Search' + noSearchResults, //GA4 name: "search"
                            request: request,
                            term: request.term.toLowerCase(),
                            noResults: ( noSearchResults )? true : false,
                        nebula.dom.document.trigger('nebula_event', thisEvent);
                        ga('send', 'event', thisEvent.category, thisEvent.action, thisEvent.term);
                        nebula.fbq('track', 'Search', {search_string: thisEvent.term});
                        nebula.clarity('set', thisEvent.category, thisEvent.term);
                        nebula.crm('identify', {internal_search: thisEvent.term});
                    }, 1500, 'autocomplete success buffer');
                    ga('send', 'timing', 'Autocomplete Search', 'Server Response', Math.round(nebula.timer('(Nebula) Autocomplete Search', 'lap')), 'Each search until server results');
                    sourceResponse(searchResults); //Respond to the jQuery UI Autocomplete now
                    element.closest('.input-group, .nebula-input-group').find('.fa-spin').removeClass('fa-spin fa-spinner').addClass('fa-search');
                focus: function(event, ui){
                    event.preventDefault(); //Prevent input value from changing.
                select: function(event, ui){
                    let thisEvent = {
                        category: 'Internal Search',
                        action: 'Autocomplete Click', //GA4 name: "select_content"
                        ui: ui,
                        label: ui.item.label,
                        external: ( typeof ui.item.external !== 'undefined' )? true : false,
                    ga('set',, 1);
                    nebula.dom.document.trigger('nebula_autocomplete_search_selected', thisEvent.ui);
                    nebula.dom.document.trigger('nebula_event', thisEvent);
                    ga('send', 'event', thisEvent.category, thisEvent.action, thisEvent.label);
                    ga('send', 'timing', 'Autocomplete Search', 'Until Navigation', Math.round(nebula.timer('(Nebula) Autocomplete Search', 'end')), 'From first initial search until navigation');
                    if ( thisEvent.external ){
              , '_blank');
                    } else {
                        window.location.href =;
                open: function(){
                    let heroAutoCompleteDropdown = jQuery('.form-identifier-nebula-hero-search');
                    heroAutoCompleteDropdown.css('max-width', element.outerWidth());
                close: function(){
                minLength: 3, //Require at least 3 characters
            }).data('ui-autocomplete')._renderItem = function(ul, item){
                let thisSimilarity = ( typeof item.similarity !== 'undefined' )? item.similarity.toFixed(1) + '% Match' : '';
                let listItem = jQuery("<li class='" + item.classes + "' title='" + thisSimilarity + "'></li>").data("item.autocomplete", item).append("<a href='" + + "'> " + item.label.replaceAll(/\\/g, '') + "</a>").appendTo(ul);
                return listItem;
            let thisFormIdentifier = element.closest('form').attr('id') || element.closest('form').attr('name') || element.closest('form').attr('class');
            element.autocomplete('widget').addClass('form-identifier-' + thisFormIdentifier);


    To override or disable this JavaScript function, simply redeclare it with the exact same function name.

    nebula.autocompleteSearch = function(element, types){
        //Write your own code here, leave it blank, or return false.