Guided Search
On this page
Facets are a great way to let your users refine their search, but it can be overwhelming for them to find the right ones if they see a long list of facets. A solution to this problem is to guide your users’ discovery experience by showing them the most used category of facets at the top close to the search bar.
In this image, and in the live demo, you see a set of guided search facets appear near the search bar. For example, if you are looking for computers, instead of typing out the query, you can click on Computer & Tablets to select the category facet filters. Not only do the results on the page get updated, the rest of the facet filters are also updated to stay contextual to the scope of the query. After you click on the Computer & Tablets facet, the brand facets get updated to show all the relevant brands such as HP and Apple. This guides your users to refine and improve the relevance of their results. The order of the facet values are based on count but can be easily adjusted to alphabetical order or any custom order that makes sense for your business.
Requirements
Difficulty |
|
Prerequisites | Instant Search 4+ |
Implementation guide
In this guide, you build a classic ecommerce search page with a search box, guided search facets at the top, two facets (brand and price), and results. The guide will focus on how to build the guided search facets with InstantSearch JS.
High level approach
To create guided search facets, you need to create your own UI of the refinementList
widget using connectors. Essentially, you override the out-of-the-box behavior of a refinement list widget with your own render function. You can find the code examples in the guide on the custom refinement list connector.
Before you get started, please make sure you:
- Select an attribute as the guided facet filter and set it as one of the
attributesForFaceting
. - Set up your UI with the InstantSearch getting started guide.
File and index structure
For this implementation, you need two files:
index.html
main.js
You also need an Algolia index containing the ecommerce dataset. For this guide, name the index instant_search_solutions_ecommerce
.
It’s a 3-step process (this code is located in main.js
):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1. Create a render function
const renderRefinementList = (renderOptions, isFirstRender) => {
// Rendering logic
};
// 2. Create the custom widget
const customRefinementList = instantsearch.connectors.connectRefinementList(
renderRefinementList
);
// 3. Instantiate
search.addWidgets([
customRefinementList({
// instance params
})
]);
Create a render function
The rendering function is called before the query and each time results come back from Algolia. The function in main.js
is populated with rendering options. This code creates the look and feel of the category’s facet values and defines the click-event behavior. It also manages the “show more” logic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 1. Create a render function
const renderRefinementList = (renderOptions, isFirstRender) => {
const {
items,
refine,
createURL,
isShowingMore,
toggleShowMore,
widgetParams,
} = renderOptions;
//Do some initial rendering and bind events
if (isFirstRender) {
const ul = document.createElement('ul');
const button = document.createElement('button');
button.classList.add('btn-showMore')
button.textContent = 'Show more';
button.addEventListener('click', () => {
toggleShowMore();
});
widgetParams.container.appendChild(ul);
widgetParams.container.appendChild(button);
}
//Render the widget
widgetParams.container.querySelector('ul').innerHTML = items
.map(
item => `
<li style="${isRefined(item)}">
<a
href="${createURL(item.value)}"
data-value="${item.value}"
>
${item.label} (${item.count})
</a>
</li>
`
)
.join('');
[...widgetParams.container.querySelectorAll('a')].forEach(element => {
element.addEventListener('click', event => {
event.preventDefault();
refine(event.currentTarget.dataset.value);
});
});
const button = widgetParams.container.querySelector('button');
button.textContent = isShowingMore ? 'Show less' : 'Show more';
};
function isRefined(item) {
if (item.isRefined) {
return 'font-weight: bold; background-color: rgba(83,101,252, 0.5)'
}
}
Create the custom refinementList
connector
1
2
3
4
// 2. Create the custom widget
const customRefinementList = instantsearch.connectors.connectRefinementList(
renderRefinementList
);
Instantiate the custom refinementList
connector
Finally, you add the new customized connector to your collection of widgets also in main.js
. You give it the container used by the HTML, as described in the next section. In the example, the container ID is #guided-search-facets
.
1
2
3
4
5
6
7
8
// 3. Instantiate
search.addWidgets([
customRefinementList({
document.querySelector('#guided-search-facets')
attribute: 'categories',
showMoreLimit: 40,
})
]);
Update the HTML
Last step is to add the widget to your index.html
. Here it’s positioned just under the search bar.
1
2
<div id="searchbox" class="searchbox"></div>
<div id="guided-search-facets" class="guided-search-facets"></div>