Skip to main content

Add predictive search to your theme

You can add predictive search to your theme so that suggested results appear immediately as you type into the search field. Predictive search helps customers articulate and refine their search queries, and provides new ways for them to explore an online store. It also lets them quickly browse matches without having to leave their current page to see a separate list of search results.

Example of search dropdown showing recommended products

Predictive search supports suggestions for products, collections, queries, pages, and articles.

Before implementing predictive search in your theme, it's important to be familiar with how suggestions are generated, current API limitations, and the UX guidelines.


Anchor to How suggestions are generatedHow suggestions are generated

The predictive search dropdown displays the following information when you enter a query.

Diagram of search dropdown
Legend for the diagram of the search dropdown
PointDescription
1Predictive search dropdown
2Query suggestions
3Collection suggestions
4Product suggestions
5Page suggestions
6Article suggestions

After you start typing into the search bar, predictive search suggests results that are related to what you’re typing. They match search terms either exactly or with typo tolerance on searchable properties of shop resources.

Matching products or variants are returned as product suggestions that drop down from the search bar. For example, you’re looking for a snowboard and type very-fast snowbo. Product suggestions appear for products or variants that contain very, fast, and a term that begins with snowbo.

If a word is separated by a hyphen or space, then it will be considered as two terms. Words or phrases that are separated into multiple terms return different results than a single term that includes the same words. For example, T-shirt and t shirt return the same results, but tshirt does not.

Product variants are returned only when the query matches terms specific to the variant title. Only the variants with the most matching terms are returned as results. For example, a store has a snowboard with a blue variant and a light blue variant. If you search for snowbo, then the snowboard product is returned. However, if you search for light blue snowbo, then only the light blue variant is returned.

Query suggestions are generated by extracting words and phrases from your product catalog, as well as from customer searches, using natural language processing techniques.



To support predictive search, you need to implement the following components:

The main search is a search input for the predictive search functionality to apply to.

/sections/main-search.liquid

<script src="{{ 'predictive-search.js' | asset_url }}" defer="defer"></script>

<predictive-search>
<form action="{{ routes.search_url }}" method="get" role="search">
<label for="Search">Search</label>
<input
id="Search"
type="search"
name="q"
value="{{ search.terms | escape }}"
role="combobox"
aria-expanded="false"
aria-owns="predictive-search-results"
aria-controls="predictive-search-results"
aria-haspopup="listbox"
aria-autocomplete="list"
/>
<input name="options[prefix]" type="hidden" value="last" />

<div id="predictive-search" tabindex="-1"></div>
</form>
</predictive-search>

Anchor to The predictive search sectionThe predictive search section

The predictive search section hosts the predictive search results. These results are output by looping through the resources attribute of the predictive_search object.

This section is rendered with the main search using the JavaScript function.

The following example renders the products from the search results. For a more complex template that accepts all resource types, refer to Dawn's source files.

/sections/predictive-search.liquid

{%- if predictive_search.performed -%}
<div id="predictive-search-results">
{%- if predictive_search.resources.products.size > 0 -%}
<h3 id="predictive-search-products">
Products
</h3>
<ul role="listbox" aria-labelledby="predictive-search-products">
{%- for product in predictive_search.resources.products -%}
<li role="option">
<a href="{{ product.url }}">
{{ product | image_url: width: 50 | image_tag }}
<span>{{ product.title }}</span>
</a>
</li>
{%- endfor -%}
</ul>
{%- endif -%}
<button>
Search for “{{ predictive_search.terms }}
</button>
</div>
{%- endif -%}

Anchor to The JavaScript functionThe JavaScript function

The predictive_search object isn't defined when the predictive search section is initially rendered, so you need to retrieve the populated section content using the section response of the Predictive Search API.

The following example uses the default parameters for the Predictive Search API, but you can customize them to fit your needs.

Tip

It's recommended to use the Liquid routes object to dynamically set the endpoint URL for the fetch call.

/assets/predictive-search.js

class PredictiveSearch extends HTMLElement {
constructor() {
super();

this.input = this.querySelector('input[type="search"]');
this.predictiveSearchResults = this.querySelector('#predictive-search');

this.input.addEventListener('input', this.debounce((event) => {
this.onChange(event);
}, 300).bind(this));
}

onChange() {
const searchTerm = this.input.value.trim();

if (!searchTerm.length) {
this.close();
return;
}

this.getSearchResults(searchTerm);
}

getSearchResults(searchTerm) {
fetch(`/search/suggest?q=${searchTerm}&section_id=predictive-search`)
.then((response) => {
if (!response.ok) {
var error = new Error(response.status);
this.close();
throw error;
}

return response.text();
})
.then((text) => {
const resultsMarkup = new DOMParser().parseFromString(text, 'text/html').querySelector('#shopify-section-predictive-search').innerHTML;
this.predictiveSearchResults.innerHTML = resultsMarkup;
this.open();
})
.catch((error) => {
this.close();
throw error;
});
}

open() {
this.predictiveSearchResults.style.display = 'block';
}

close() {
this.predictiveSearchResults.style.display = 'none';
}

debounce(fn, wait) {
let t;
return (...args) => {
clearTimeout(t);
t = setTimeout(() => fn.apply(this, args), wait);
};
}
}

customElements.define('predictive-search', PredictiveSearch);

Was this page helpful?