Custom Query Suggestions

There are several ways of adding query suggestions to your search box. The simplest is to utilize pre-built Atomic components such as atomic-search-box-recent-queries and atomic-search-box-query-suggestions. Another way is to use your own custom suggestions. This article shows you how to do so. This could be useful, for example, if you want to retrieve suggestions from an API external to Coveo.

For custom suggestions to integrate well with existing Atomic components, the Atomic Library offers a function called dispatchSearchBoxSuggestionsEvent. You can take a look at the usage of this function, along with the relevant reference documentation in the sections below.

Complete Code Example

The following code sample shows you how to leverage dispatchSearchBoxSuggestionsEvents to provide custom query suggestions returned from a third-party API. You can copy paste it, as is, to start playing with the concepts discussed in this article.

<!DOCTYPE html>
<html>
    <head>
        <title>Custom Query Suggestions</title>
        <script type="module" src="https://static.cloud.coveo.com/atomic/v1/atomic.esm.js"></script>
        <link rel="stylesheet" href="https://static.cloud.coveo.com/atomic/v1/themes/coveo.css"/>
        <script type="module">
            import {dispatchSearchBoxSuggestionsEvent} from 'https://static.cloud.coveo.com/atomic/v1/index.esm.js';

            function registerCustomSuggestions() {
              class CustomSuggestions extends HTMLElement {
                constructor() {
                  super();
                }

                suggestions = [];

                renderSuggestions(bindings) { 4
                  return this.suggestions.slice(0, 2).map((suggestion) => {
                    const content = document.createElement('div');
                    content.innerText = suggestion;
                    return {
                      key: suggestion,
                      query: suggestion,
                      onSelect: () => {
                        bindings.searchBoxController.updateText(suggestion);
                        bindings.searchBoxController.submit();
                      },
                      content,
                    };
                  });
                }

                onInput(bindings) { 3
                  const query = bindings.searchBoxController.state.value;

                  return fetch('https://pokeapi.co/api/v2/pokemon')
                    .then((res) => res.json())
                    .then((res) => {
                      const resultsWithQuery = query ? results.filter((r) => r.name.includes(query[0])) : results;
                      this.suggestions = resultsWithQuery.slice(0, 10).map((r) => r.name);
                    });
                }

                async connectedCallback() {
                  dispatchSearchBoxSuggestionsEvent((bindings) => { 1
                    return { 2
                      position: 2,
                      onInput: () => this.onInput(bindings),
                      renderItems: () => this.renderSuggestions(bindings),
                    };
                  }, this);
                }
              }

              window.customElements.define('custom-suggestions', CustomSuggestions); 5
            }

            async function main() {
              await customElements.whenDefined('atomic-search-interface');
              const searchInterface = document.querySelector('atomic-search-interface');
              await searchInterface.initialize({
                accessToken: '<ACCESS_TOKEN>',
                organizationId: '<ORGANIZATION_ID>',
              });

              const engine = searchInterface.engine;
              searchInterface.executeFirstSearch();
            }

            main();
            registerCustomSuggestions();
        </script>
    </head>
    <body>
        <atomic-search-interface id="search">
        <atomic-search-layout>
            <atomic-layout-section section="search">
                <atomic-search-box>
                  <custom-suggestions></custom-suggestions> 6
                </atomic-search-box>
            </atomic-layout-section>
            <atomic-layout-section section="main">
                <atomic-layout-section section="results">
                    <atomic-result-list></atomic-result-list>
                </atomic-layout-section>
            </atomic-layout-section>
        </atomic-search-layout>
        </atomic-search-interface>
    </body>
</html>
1 Pass bindings as input for the SearchBoxSuggestionsEvent callback.
2 The callback function needs to return a SearchBoxSuggestions object with certain required properties, as detailed in the reference below.
3 onInput accesses the current query by using the state of the searchBoxController. It then makes a call to an API outside of Coveo and returns a list of matching results if they included the current query. These results are saved to be provided as suggestions.
4 The results saved from the previous step are proccessed and converted into a SearchBoxSuggestionElement object with a unique key, the query to be suggested and the HTML content to be displayed for the suggestions. In addition to these, an onSelect callback is defined so that whenever the suggestion is selected by the user, the search box display text is updated and a search query is triggered.
5 A new custom HTML element is defined based on the CustomSuggestions class.
6 The newly defined custom element can be placed as a child of the <atomic-search-box> component to provide custom query suggestions.

Reference

Take a look at Atomic project repository for more information about the data types and methods detailed here.

dispatchSearchBoxSuggestionsEvent

Dispatches an event which retrieves the SearchBoxSuggestionsBindings on a configured parent search box.

Parameters

  • event: SearchBoxSuggestionsEvent (required)

    Event sent from the registered query suggestions to the parent search box.

  • element: HTMLElement (required)

    Element on which to dispatch the event, which must be the child of a configured search box.

Returns void

SearchBoxSuggestionsEvent

Event sent from the registered query suggestions to the parent search box.

Parameters

SearchBoxSuggestionElement

Element which will be rendered in the list of suggestions.

Property Description Type

key (required)

Stable identity which enables Stencil to reuse DOM elements for better performance. The best way to pick a key is to use a string that uniquely identifies that list item among its siblings (often your data will already have IDs).

string

content (required)

Rendered content of the element.

Element | VNode

onSelect

Hook called when the selection is selected.

(e: Event) ⇒ void

query

The query associated with the suggestion which will replace the query in the search box if the suggestion is selected.

string

ariaLabel

For improved accessibility, provide this property with additional information. See Aria Label.

string

part

Adds a specific shadow part attribute that can be selected with the CSS ::part pseudo-element.

string

hideIfLast

Hide the suggestion if it’s the last in the list.

boolean

SearchBoxSuggestions

List of suggestions that will be displayed along other lists (e.g recent queries) when the search box’s input is selected. This will contain a list of SearchBoxSuggestionElement objects.

Property Description Type

position (required)

The search box will sort the position of suggestions using this value. The lowest value being first. Atomic provided suggestions, by default, use the DOM.

number

panel

Whether the suggestions should be listed in the right or left panel. By default, the suggestions are listed in the left panel.

string

renderItems (required)

Method that returns the list of elements which will be rendered in the list of suggestions.

() ⇒ SearchBoxSuggestionElement[];

onInput

Hook called when the user changes the search box’s input value. This can lead to all the query suggestions being updated.

() ⇒ Promise<unknown> | void

onSuggestedQueryChange

Hook called when the suggested query changes as a user traverses through the list of suggestions. This is used for instant results, which are rendered based on the current suggested query.

(q: string) ⇒ Promise<unknown> | void

SearchBoxSuggestionsBindings

The bindings passed from the search box to the suggestions. This object gives you access to the state of the suggestion system as a whole and has important information and functions that you can invoke.

Property Description Type

id

The unique id of the search box.

string

isStandalone

Whether the search box is standalone.

boolean

searchBoxController

The search box headless controller.

searchBoxController

numberOfQueries

The amount of queries displayed when the user interacts with the search box. This is a property set on the atomic-search-box component.

number

clearFilters

Whether to clear all active query filters when the end user submits a new query from the search box.

boolean

suggestedQuery

Retrieves the suggested query, meaning the query that would be sent if the search were executed. The suggested query changes as a user traverses through the list of suggestions.

() ⇒ string

clearSuggestions

Removes the current suggestions.

() ⇒ void

triggerSuggestions

Triggers update & retrieval of all suggestions.

() ⇒ void

getSuggestions

Retrieves the current suggestions.

() ⇒ SearchBoxSuggestions[]

getSuggestionElements

Retrieves the currently suggested elements.

() ⇒ SearchBoxSuggestionElement[]