--- title: Build search interfaces (CSR) slug: p25a2501 canonical_url: https://docs.coveo.com/en/p25a2501/ collection: coveo-for-commerce source_format: adoc --- # Build search interfaces (CSR) Building a search interface with Coveo Headless involves two main components: a search box and a search page. Headless provides two types of search box controllers: [`SearchBox`](https://docs.coveo.com/en/headless/latest/reference/types/Commerce.SearchBox.html) and [`StandaloneSearchBox`](https://docs.coveo.com/en/headless/latest/reference/interfaces/Commerce.StandaloneSearchBox.html). It also offers a [`Search`](https://docs.coveo.com/en/headless/latest/reference/interfaces/Commerce.Search.html) controller to manage the search page and results. * `SearchBox`: Use this controller to create a search box component in your search interface, submit queries, and display [query suggestions](https://docs.coveo.com/en/1015/). This controller is used on the search page itself. * `StandaloneSearchBox`: Use this controller to create a standalone search box that redirects to your search page. This controller is used on every page of your app except the search page. * `Search`: Use this controller to manage search results, such as facets, sorting, and pagination, ensuring a seamless user experience. Complete examples are available in the [Headless repository](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-commerce-react/src/pages/search-page.tsx). ## Prerequisite Make sure that you understand how to [build commerce search pages](https://docs.coveo.com/en/o4ue0200/). ## Creating a search box To create a search box, use the `SearchBox` and `StandaloneSearchBox` controllers. ### Using the `SearchBox` controller The following code snippet shows how to create a [`SearchBox`](https://docs.coveo.com/en/headless/latest/reference/types/Commerce.SearchBox.html) controller. ```tsx import { engine } from './Engine'; import { buildSearchBox } from '@coveo/headless/commerce'; const searchBox = buildSearchBox(engine); <1> ``` <1> Build the `SearchBox` controller by passing in the [previously initialized engine](https://docs.coveo.com/en/o6r70022#initialize-the-headless-commerce-engine). Next, create a search box component that uses the `SearchBox` controller. ```tsx import { SearchBox as HeadlessSearchBox } from '@coveo/headless/commerce'; import { useEffect, useState } from 'react'; interface ISearchBoxProps { controller: HeadlessSearchBox; } export default function SearchBox(props: ISearchBoxProps) { const {controller} = props; const [state, setState] = useState(controller.state); useEffect(() => { <1> controller.state.value && controller.clear(); controller.subscribe(() => setState(controller.state)); }, [controller]); return (
value={state.value} onChange={(e) => controller.updateText(e.target.value)} > {state.value !== '' && ( <3> )} <4> {state.suggestions.length > 0 && ( <5> )}
); } ``` <1> Subscribe to the state of the `SearchBox` controller. This allows you to update the search box component when the state of the controller changes. <2> Create an input field to allow users to enter their search queries. As the user types in the search box, call the `updateText` method on the `SearchBox` controller to update the query. <3> Display a clear button when the search box is not empty. When the user clicks the clear button, call the `clear` method on the `SearchBox` controller to clear the search box. <4> Render a search button that calls the `submit` method on the `SearchBox` controller to submit the query. <5> Display query suggestions when the user types in the search box. When the user clicks a suggestion, call the `selectSuggestion` method on the `SearchBox` controller to submit the selected suggestion. This component can now be included in your search page. #### Using the `StandaloneSearchBox` controller In addition to creating a search box component, create a lightweight standalone search box component that utilizes the [`StandaloneSearchBox`](https://docs.coveo.com/en/headless/latest/reference/interfaces/Commerce.StandaloneSearchBox.html) controller to redirect to your search page. This component should be included on every page of your app except the search page. Before creating the component, initialize the controller. ```tsx import { engine } from './Engine'; import { buildStandaloneSearchBox } from '@coveo/headless/commerce'; const standaloneSearchBox = buildStandaloneSearchBox(engine, { <1> options: { redirectionUrl: '/search' } }); ``` <1> Build the `StandaloneSearchBox` controller by passing in the previously initialized engine and the redirection URL to the search page. When the user submits a query in this search box, the `state.redirectTo` is updated to `/search`. This update can be detected by subscribing to the controller state and then used to redirect the user to the search page. Next, create a component that uses this `StandaloneSearchBox` controller. ```tsx import { StandaloneSearchBox as HeadlessStandaloneSearchBox } from '@coveo/headless/commerce'; import { useEffect, useState } from 'react'; interface IStandaloneSearchBoxProps { navigate: (url: string) => void; <1> controller: HeadlessStandaloneSearchBox; } export default function StandaloneSearchBox(props: IStandaloneSearchBoxProps) { const {navigate, controller} = props; const [state, setState] = useState(controller.state); useEffect(() => { <2> controller.state.value && controller.clear(); controller.subscribe(() => setState(controller.state)); }, [controller]); useEffect(() => { <3> if (state.redirectTo === '/search') { navigate(`${state.redirectTo}#q=${state.value}`); controller.afterRedirection(); } else if (state.redirectTo !== '') { window.location.href = state.redirectTo; } }, [state.redirectTo, navigate, state.value, controller]); return (
value={state.value} onChange={(e) => controller.updateText(e.target.value)} > {state.value !== '' && ( <5> )} <6> {state.suggestions.length > 0 && ( <7> )}
); } ``` <1> Define a `navigate` function to redirect to the search page. <2> Subscribe to the state of the `StandaloneSearchBox` controller. <3> Redirect to the search page when the user submits a query and the `redirectTo` property of the controller is set to `/search`. Call the `afterRedirection` method on the controller to reset the state after the redirection. <4> Create an input field to allow users to enter their search queries. <5> Display a clear button when the search box is not empty. <6> Render a search button that calls the `submit` method on the `StandaloneSearchBox` controller to submit the query. <7> Display query suggestions when the user types in the search box. When the user clicks a suggestion, call the `selectSuggestion` method on the `StandaloneSearchBox` controller to submit the selected suggestion as a query. A complete example, including a sample implementation of the standalone search box component, is available in the [Headless repository](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-commerce-react/src/components/standalone-search-box/standalone-search-box.tsx). ## Displaying the search page with the `Search` controller In addition to rendering the search box, you must display the search results on the search page. First, initialize the [`Search`](https://docs.coveo.com/en/headless/latest/reference/interfaces/Commerce.Search.html) controller. ```tsx import { engine } from './Engine'; import { buildSearch } from '@coveo/headless/commerce'; const searchController = buildSearch(engine); ``` Next, use this controller in a component to render the search page. ```tsx import { Cart, Search as HeadlessSearch, ProductListing, } from '@coveo/headless/commerce'; import { useState, useEffect } from 'react'; import FacetGenerator from '../../facets/facet-generator/facet-generator'; import Pagination from '../../pagination/pagination'; import ProductList from '../../product-list/product-list'; import Sort from '../../sort/sort'; interface ISearchAndListingInterface { searchOrListingController: HeadlessSearch | ProductListing; cartController: Cart; navigate: (pathName: string) => void; } export default function SearchAndListingInterface( props: ISearchAndListingInterface ) { const {searchOrListingController, cartController, navigate} = props; const [searchOrListingState, setSearchOrListingState] = useState( searchOrListingController.state ); useEffect(() => { <1> searchOrListingController.subscribe(() => setSearchOrListingState(searchOrListingController.state) ); }, [searchOrListingController]); return (
controller={searchOrListingController.facetGenerator()} />
<3> products={searchOrListingState.products} controllerBuilder={searchOrListingController.interactiveProduct} cartController={cartController} navigate={navigate} > <5>
); } ``` <1> Subscribe to the state of the `Search` controller. <2> [Display the facets generated by the `FacetGenerator` sub-controller](https://docs.coveo.com/en/o7vb0270/). <3> [Display the sorting options generated by the `Sort` sub-controller](https://docs.coveo.com/en/o7vb0270/). <4> [Render the list of `products` returned by the search](https://docs.coveo.com/en/o8ce0239/). <5> [Display the pagination generated by the `Pagination` sub-controller](https://docs.coveo.com/en/o7vb0270/). > **Note** > > The previous component can be re-used for both displaying and interacting with results from both search and listing pages. A complete example of how to build a search page is available in the [Headless repository](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-commerce-react/src/components/use-cases/search-and-listing-interface/search-and-listing-interface.tsx). Within the sample project, you can find additional components that were omitted in this article, such as the [`BreadcrumbManager`](https://docs.coveo.com/en/headless/latest/reference/interfaces/Commerce.Search.html#breadcrumbmanager) (displays a summary of the currently active facet values) and [`Summary`](https://docs.coveo.com/en/headless/latest/reference/interfaces/Commerce.Search.html#summary) (provides a summary of search results such as the number of results returned).