--- title: Implement filter suggestions and instant products (CSR) slug: o8ce0240 canonical_url: https://docs.coveo.com/en/o8ce0240/ collection: coveo-for-commerce source_format: adoc --- # Implement filter suggestions and instant products (CSR) To improve the functionality of your search box, you can implement filter suggestions and instant products. * Filter suggestions are a content discovery feature connected to search boxes and [facets](https://docs.coveo.com/en/198/). When end-users start typing in a search box, Coveo for Commerce suggests relevant [fields](https://docs.coveo.com/en/200/) and field values to use as filters. The end-user can select one of these filter suggestions to filter the results with a [facet](https://docs.coveo.com/en/198/) on the selected field value. ![Coveo search box autocompletes with filter suggestions while page shows product results updating](https://docs.coveo.com/en/assets/images/headless/filter-suggestions-demo.gif) * Instant products enhance the search experience by displaying relevant products in real time as users type in the search box. The end-user can then select a product straight from the search box. ![Coveo Headless Commerce search UI updates product list in real time while user types query](https://docs.coveo.com/en/assets/images/headless/instant-results-demo.gif) This article explains how to implement filter suggestions and instant products in Coveo for Commerce with Coveo Headless in a client-side rendering scenario. It uses an example from the [Coveo Headless repository](https://github.com/coveo/ui-kit/tree/main/samples/headless/commerce-react). ## Prerequisites To implement filter suggestions and instant products, you must: * Have created a [Predictive Query Suggestion model](https://docs.coveo.com/en/lcee0589/) or [Query Suggestion model](https://docs.coveo.com/en/p26b0268/), and have implemented [query suggestions](https://docs.coveo.com/en/1015/) in your [search box](https://docs.coveo.com/en/p25a2501/). * Have made the facet fields you want to use for suggestion candidates eligible for filter suggestions in the [Coveo Merchandising Hub (CMH)](https://docs.coveo.com/en/o5290573/). See [Modify facet fields](https://docs.coveo.com/en/p3oa0420#modify-facet-fields) to learn how to enable filter suggestions for facet fields. ## Headless implementation Implement these features in [Coveo Headless](https://docs.coveo.com/en/lcdf0493/) as follows: * Use the [`FilterSuggestionsGenerator`](https://docs.coveo.com/en/headless/latest/reference/interfaces/Commerce.FilterSuggestionsGenerator.html) controller to access and display filter suggestions. The [Coveo Headless repository](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-commerce-react/src/components/filter-suggestions) contains a sample implementation of filter suggestions. * Use the [`InstantProducts`](https://docs.coveo.com/en/headless/latest/reference/interfaces/Commerce.InstantProducts.html) controller to access and display instant products. The [`InstantProducts`](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-commerce-react/src/components/instant-products/instant-products.tsx) controller in the Coveo Headless repository contains a sample implementation of instant products. This section explains the key parts of the implementation. ### Initialize the target controllers In the pages where you include your search box and your standalone search box, initialize the `InstantProducts` and `FilterSuggestionsGenerator` controllers and pass them to the search box and standalone search box components. See the [layout.tsx](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-commerce-react/src/layout/layout.tsx) file in the sample project for a full example. ```tsx // src/layout/layout.tsx // ... const standaloneSearchBoxId = 'standalone-search-box'; // ... engine )} filterSuggestionsGeneratorController={buildFilterSuggestionsGenerator( <2> engine )} /> // ... ``` <1> Uses the [`buildInstantProducts`](https://docs.coveo.com/en/headless/latest/reference/functions/Commerce.buildInstantProducts.html) function to create the `InstantProducts` controller. <2> Uses the [`buildFilterSuggestionsGenerator`](https://docs.coveo.com/en/headless/latest/reference/functions/Commerce.buildFilterSuggestionsGenerator.html) function to create the `FilterSuggestionsGenerator` controller. ### Implement a filter suggestion generator component To display filter suggestions in your search box components, implement a component that displays the filter suggestions using the `FilterSuggestions` controller. ```tsx // src/components/filter-suggestions/filter-suggestions-generator.tsx import { FilterSuggestionsGenerator as HeadlessFilterSuggestionsGenerator, FilterSuggestions as HeadlessFilterSuggestions, CategoryFilterSuggestions, RegularFacetSearchResult, CategoryFacetSearchResult, } from '@coveo/headless/commerce'; import {useEffect, useState} from 'react'; import FilterSuggestions from './filter-suggestions.js'; <1> interface IFilterSuggestionsGeneratorProps { controller: HeadlessFilterSuggestionsGenerator; onClickFilterSuggestion: ( <2> controller: HeadlessFilterSuggestions | CategoryFilterSuggestions, value: RegularFacetSearchResult | CategoryFacetSearchResult ) => void; } export default function FilterSuggestionsGenerator( props: IFilterSuggestionsGeneratorProps ) { const {controller, onClickFilterSuggestion} = props; const [filterSuggestionsState, setFilterSuggestionsState] = useState( controller.filterSuggestions ); useEffect(() => { controller.subscribe(() => { setFilterSuggestionsState(controller.filterSuggestions); }); }, [controller]); if (filterSuggestionsState.length === 0) { return null; } return (
{filterSuggestionsState.map((filterSuggestionsController) => { return ( ); })}
); } ``` <1> The `FilterSuggestions` component will display the filter suggestions for a given [facet](https://docs.coveo.com/en/198/). It's defined by the function definitions underneath it. <2> The `onClickFilterSuggestion` function is called when the user clicks a filter suggestion. It's passed as a prop and is defined in the callback function types underneath it. See the [Use your components in your search box](#use-your-components-in-your-search-box) section for more information. The `FilterSuggestions` component is defined as follows. ```tsx // src/components/filter-suggestions/filter-suggestions.tsx import { CategoryFacetSearchResult, CategoryFilterSuggestions, FilterSuggestions as HeadlessFilterSuggestions, RegularFacetSearchResult, } from '@coveo/headless/commerce'; import {useEffect, useState} from 'react'; interface IFilterSuggestionsProps { controller: HeadlessFilterSuggestions | CategoryFilterSuggestions; onClickFilterSuggestion: ( controller: HeadlessFilterSuggestions | CategoryFilterSuggestions, value: RegularFacetSearchResult | CategoryFacetSearchResult ) => void; } export default function FilterSuggestions(props: IFilterSuggestionsProps) { const {controller, onClickFilterSuggestion} = props; const [state, setState] = useState(controller.state); useEffect(() => { controller.subscribe(() => { setState(controller.state); }); }, [controller]); if (state.values.length === 0) { return null; } const renderFilterSuggestionButton = ( value: RegularFacetSearchResult | CategoryFacetSearchResult ) => { return ( ); }; return (

{state.displayName} suggestions

); } ``` <1> This component supports both [hierarchical](https://docs.coveo.com/en/headless/latest/reference/types/Commerce.CategoryFacet.html) and regular [facets](https://docs.coveo.com/en/headless/latest/reference/types/Commerce.RegularFacet.html). ### Implement an instant products component To display instant products in your search box components, implement a component that displays the instant products using the `InstantProducts` controller. ```tsx // src/components/instant-products/instant-products.tsx import { InstantProducts as HeadlessInstantProducts, Product, } from '@coveo/headless/commerce'; import {useEffect, useState} from 'react'; interface IInstantProductProps { controller: HeadlessInstantProducts; navigate: (pathName: string) => void; } export default function InstantProducts(props: IInstantProductProps) { const {controller, navigate} = props; const [state, setState] = useState(controller.state); useEffect( () => controller.subscribe(() => setState({...controller.state})), [controller] ); if (state.products.length === 0 || !state.query) { return null; } const onClickProduct = (product: Product) => { controller.interactiveProduct({options: {product}}).select(); // navigate to the product page }; return (
{state.products.length === 0 ? (

No instant products for query {state.query}

) : ( <>

Instant products for query {state.query}

)}
); } ``` ### Use your components in your search box In your search box and standalone search box components, use the `FilterSuggestionsGenerator` component to display the filter suggestions and the `InstantProducts` component to display the instant products. For example, see the [standalone-search-box.tsx](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-commerce-react/src/components/standalone-search-box/standalone-search-box.tsx) file in the sample project. ```tsx // src/components/standalone-search-box/standalone-search-box.tsx // ... interface IStandaloneSearchBoxProps { navigate: (url: string) => void; ssbController: HeadlessStandaloneSearchBox; instantProductsController: HeadlessInstantProducts; filterSuggestionsGeneratorController: HeadlessFilterSuggestionsGenerator; } export default function StandaloneSearchBox(props: IStandaloneSearchBoxProps) { const { navigate, ssbController, instantProductsController, filterSuggestionsGeneratorController, } = props; const [ssbState, setSsbState] = useState(ssbController.state); const [isDropdownVisible, setIsDropdownVisible] = useState(false); // ... const fetchFilterSuggestions = (value: string) => { <1> for (const filterSuggestions of filterSuggestionsGeneratorController.filterSuggestions) { filterSuggestions.updateQuery(value); } }; const clearFilterSuggestions = () => { <2> for (const filterSuggestions of filterSuggestionsGeneratorController.filterSuggestions) { filterSuggestions.clear(); } }; // ... const onSearchBoxInputChange = (e: React.ChangeEvent) => { // ... ssbController.updateText(e.target.value); // ... fetchFilterSuggestions(e.target.value); <3> instantProductsController.updateQuery(e.target.value); <4> }; const onSearchBoxInputKeyDown = ( e: React.KeyboardEvent ) => { switch (e.key) { case 'Escape': // ... if (ssbState.value !== '') { // ... clearFilterSuggestions(); <5> instantProductsController.updateQuery(''); break; } break; // ... } }; const onClickSearchBoxClear = () => { // ... clearFilterSuggestions(); instantProductsController.updateQuery(state.value); }; const onFocusSuggestion = (suggestion: Suggestion) => { // ... fetchFilterSuggestions(suggestion.rawValue); instantProductsController.updateQuery(suggestion.rawValue); }; // ... const renderDropdown = () => { <6> return ( // ... controller: FilterSuggestions | CategoryFilterSuggestions, value: RegularFacetSearchResult | CategoryFacetSearchResult ) => { hideDropdown(); const parameters = controller.type === 'hierarchical' ? controller.getSearchParameters( value as CategoryFacetSearchResult ) : controller.getSearchParameters( value as RegularFacetSearchResult ); navigate(`/search#${parameters}`); <8> }} //... />
) }; return (
onKeyDown={onSearchBoxInputKeyDown} ref={searchInputRef} value={ssbState.value} />
); ``` <1> Defines a function to fetch filter suggestions. <2> Similarly, defines a function to clear the filter suggestions. <3> The `onSearchBoxInputChange` function is called when the user types in the search box. Update it to call `fetchFilterSuggestions` after the standalone search box controller has updated the engine state with the new query. <4> Similarly, update the `instantProductsController` with the new query. <5> Use the `clearFilterSuggestions` functions to clear and fetch the filter suggestions when the user selects the **Escape** key. Also, update the `instantProductsController` with an empty query. Apply the same logic for other user actions, such as selecting the **Clear** button. <6> The `renderDropdown` function is called to render the filter suggestions dropdown menu. Display the `FilterSuggestionsGenerator` and `InstantProducts` components in the dropdown menu. <7> Define the function to handle the click on a filter suggestion and pass it to the `FilterSuggestionsGenerator` component. It hides the dropdown menu and navigates to the search page with the chosen filter value selected. <8> Since this is a standalone search box, the `navigate` function is used to navigate to the search page with the selected filter. <9> When users change the search box input, `onSearchBoxInputChange` is called, which updates the filter suggestions by calling `fetchFilterSuggestions`. Also, update the `instantProductsController` with the new query. Apply the same logic for other user actions, such as selecting the **Escape** key or selecting the **Clear** button.