--- title: Build search interfaces (SSR) slug: p25b0411 canonical_url: https://docs.coveo.com/en/p25b0411/ collection: coveo-for-commerce source_format: adoc --- # Build search interfaces (SSR) > **Important** > > The Headless Commerce SSR utilities are in open beta. > Contact your Coveo representative for support in adopting this. Building a [server-side rendered (SSR)](https://docs.coveo.com/en/p2af0263/) [search interface](https://docs.coveo.com/en/2741/) with Coveo Headless involves three main components: a search box, a search page, and a search provider. The Coveo Headless React package provides two types of search box controllers: the [`SearchBox`](https://docs.coveo.com/en/headless-react/latest/reference/types/SSR_Commerce.index.SearchBox.html) and the [`StandaloneSearchBox`](https://docs.coveo.com/en/headless-react/latest/reference/interfaces/SSR_Commerce.index.StandaloneSearchBox.html). It also exposes functions to create a search [provider](https://docs.coveo.com/en/obif0156#create-providers) 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 provider: Use this provider 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/main/samples/headless-ssr/commerce-nextjs/app/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 When [defining your commerce engine](https://docs.coveo.com/en/obif0156#define-the-commerce-engine-and-controllers), specify the `SearchBox` controller and retrieve the corresponding hook, as follows: ```tsx // lib/commerce-engine-config.ts import { defineSearchBox, // ... } from '@coveo/headless-react/ssr-commerce'; export default { // ... controllers: { searchBox: defineSearchBox(), // ... }, } satisfies CommerceEngineDefinitionOptions; ``` Next, create a search box component that uses the `SearchBox` controller hook. ```tsx // components/Search-box.tsx 'use client'; import { useSearchBox, } from '@/lib/commerce-engine'; export default function SearchBox() { const searchBox = useSearchBox(); <1> const onSearchBoxInputChange = (e: React.ChangeEvent) => { searchBox.methods?.updateText(e.target.value); <2> }; return (
onSearchBoxInputChange(e)} > {searchBox.state.value !== '' && ( )} {searchBox.state.suggestions.length > 0 && ( <3> )}
); } ``` <1> Retrieve the `SearchBox` controller hook. <2> Update the query when the user types in the search box by calling the [`updateText`](https://docs.coveo.com/en/headless-react/latest/reference/interfaces/SSR_Commerce.index.CoreSearchBox.html#updatetext-1) method on the `SearchBox` controller hook. <3> Display query suggestions when the user types in the search box, if suggestions are available. When the user clicks a suggestion, call the [`selectSuggestion`](https://docs.coveo.com/en/headless-react/latest/reference/interfaces/SSR_Commerce.index.CoreSearchBox.html#selectsuggestion-1) method on the `SearchBox` controller hook to submit the selected suggestion as a query. 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-react/latest/reference/interfaces/SSR_Commerce.index.StandaloneSearchBox.html) controller to redirect to your search page. This standalone search box component should be included on every page of your app except the search page. When [defining your commerce engine](https://docs.coveo.com/en/obif0156#define-the-commerce-engine-and-controllers), specify the `StandaloneSearchBox` controller and retrieve the corresponding hook. ```tsx // lib/commerce-engine-config.ts import { defineStandaloneSearchBox, // ... } from '@coveo/headless-react/ssr-commerce'; export default { // ... controllers: { standaloneSearchBox: defineStandaloneSearchBox({<1> options: {redirectionUrl: '/search'}, }), // ... }, } satisfies CommerceEngineDefinitionOptions; ``` <1> Define the `StandaloneSearchBox` controller hook by passing the redirection URL to the search page. When the user submits a query in this search box, the [`state.redirectTo`](https://docs.coveo.com/en/headless-react/latest/reference/interfaces/SSR_Commerce.index.StandaloneSearchBoxState.html#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. It looks similar to the search box component, with the addition of redirection logic. ```tsx 'use client'; import { useStandaloneSearchBox, } from '@/lib/commerce-engine'; import {useRouter} from 'next/navigation'; <1> import {useEffect} from 'react'; export default function StandaloneSearchBox() { const standaloneSearchBox = useStandaloneSearchBox(); const router = useRouter(); useEffect(() => { <2> if (standaloneSearchBox.state.redirectTo === '/search') { const url = `${standaloneSearchBox.state.redirectTo}#q=${encodeURIComponent(standaloneSearchBox.state.value)}`; router.push(url, {scroll: false}); standaloneSearchBox.methods?.afterRedirection(); <3> } }, [standaloneSearchBox.state.redirectTo, standaloneSearchBox.state.value, router, standaloneSearchBox.methods]); const onSearchBoxInputChange = (e: React.ChangeEvent) => { standaloneSearchBox.methods?.updateText(e.target.value); }; return (
onSearchBoxInputChange(e)} > {standaloneSearchBox.state.value !== '' && ( )} {standaloneSearchBox.state.suggestions.length > 0 && (
    Suggestions : {standaloneSearchBox.state.suggestions.map((suggestion, index) => (
  • ))}
)}
); } ``` <1> The Next.js [`useRouter`](https://nextjs.org/docs/pages/api-reference/functions/use-router) hook is used to access the router object and navigate to the search page. <2> Redirect to the search page when the user submits a query and the `redirectTo` property of the controller is set to `/search`. <3> This method resets the state after the redirection. 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/main/samples/headless-ssr/commerce-nextjs/components/standalone-search-box.tsx). ## Displaying the search page with the search provider In addition to rendering the search box, you must display the search results on the search page, using your search provider. ```tsx // app/search/page.tsx import ContextDropdown from '@/components/context-dropdown'; import FacetGenerator from '@/components/facets/facet-generator'; import ParameterManager from '@/components/parameter-manager'; import ProductList from '@/components/product-list'; import {SearchProvider} from '@/components/providers/providers'; import SearchBox from '@/components/search-box'; import {searchEngineDefinition} from '@/lib/commerce-engine'; import {NextJsNavigatorContext} from '@/lib/navigatorContextProvider'; import {defaultContext} from '@/utils/context'; import {buildParameterSerializer} from '@coveo/headless-react/ssr-commerce'; import {headers} from 'next/headers'; import Pagination from '@/components/pagination'; export default async function Search({ searchParams, <1> }: { searchParams: Promise; }) { const navigatorContext = new NextJsNavigatorContext(headers()); <2> searchEngineDefinition.setNavigatorContextProvider(() => navigatorContext); const {deserialize} = buildParameterSerializer(); <3> const parameters = deserialize(await searchParams); const items = // ... <4> const staticState = await searchEngineDefinition.fetchStaticState({ controllers: { cart: {initialState: [items](https://docs.coveo.com/en/210/)}, context: { language: defaultContext.language, country: defaultContext.country, currency: defaultContext.currency, view: { url: 'https://sports.barca.group/search', }, }, parameterManager: {initialState: {parameters}}, }, }); return ( staticState={staticState} navigatorContext={navigatorContext.marshal} > <6> <7>
<8>
<9> <10> <11>
); } export const dynamic = 'force-dynamic'; ``` <1> Retrieve the [search parameters](https://nextjs.org/docs/app/api-reference/file-conventions/page) from the URL. <2> [Create a navigation context provider](https://docs.coveo.com/en/obif0156#create-a-navigation-context-provider). <3> Deserialize the [search parameters](https://docs.coveo.com/en/oc685395/). <4> Retrieve [cart items](https://docs.coveo.com/en/oc685394/). <5> Wrap your components with your search [provider](https://docs.coveo.com/en/obif0156#create-providers). <6> Use your [parameter manager component](https://docs.coveo.com/en/oc685395/). <7> Let your users [change context](https://docs.coveo.com/en/obif0156#create-a-navigation-context-provider). <8> [Display the facets](https://docs.coveo.com/en/oc685396#facet-generator) generated by the `FacetGenerator` controller. <9> [Display the sorting options](https://docs.coveo.com/en/oc685396#sorting) generated by the `Sort` controller. <10> [Render the list of `products`](https://docs.coveo.com/en/oc685393/) returned by the search. <11> Display the [pagination](https://docs.coveo.com/en/oc685396#pagination) generated by the `Pagination` controller. A complete example of how to build a search page is available in the [Headless repository](https://github.com/coveo/ui-kit/tree/main/samples/headless-ssr/commerce-nextjs/app/search/page.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-react/latest/reference/types/SSR_Commerce.index.BreadcrumbManager.html) (displays a summary of the currently active facet values) and [`Summary`](https://docs.coveo.com/en/headless-react/latest/reference/interfaces/SSR_Commerce.index.Summary.html) (provides a summary of search results such as the number of results returned).