--- title: Use Coveo Search in the Salesforce Composable Storefront (PWA Kit) slug: sal3s119 canonical_url: https://docs.coveo.com/en/sal3s119/ collection: coveo-for-commerce source_format: adoc --- # Use Coveo Search in the Salesforce Composable Storefront (PWA Kit) The Salesforce Composable Storefront (also known as the PWA Kit) is built upon [React](https://reactjs.org/). [Coveo Atomic](https://docs.coveo.com/en/lcdf0264/) [supports React natively](https://docs.coveo.com/en/atomic/latest/usage/frameworks/atomic-react-wrapper), so it's the best practice to build a search UI in the Composable Storefront using the Atomic framework. This article explains the steps required to do so. > **Note** > > Instructions provided in this article apply only if you're using a Salesforce Commerce Cloud instance (previously known as Demandware). ## Create an app . Clone the [Composable Storefront repo](https://github.com/SalesforceCommerceCloud/pwa-kit/) and go to the folder where you cloned it. > **Note** > > Make sure you're using [Node.js](https://nodejs.org/) ^14.0.0. . To create a demo app, run the following command in your terminal: ```bash npx pwa-kit-create-app ``` This command will create a demo app for you. During its execution, it will prompt you to choose the Commerce Cloud instance to use in the app. For the sake of simplicity, you can choose `The Retail app with demo Commerce Cloud instance` to use a predefined cloud sandbox. . Once the app has been created, go to the app folder: ```bash cd pwa-kit-starter-project ``` ## Adjust the app to use Coveo . To use Atomic in your React project, update the package.json file with the following dependency: ```json "dependencies": { "@coveo/atomic-react": "^2.0.1", "@coveo/headless": "^2.0.1" } ``` > **Important** > > If this package throws errors while launching the app, you can try to eliminate them by changing the package version to the alpha version. > > To get the alpha version number, either visit the [Atomic React npm web page](https://www.npmjs.com/package/@coveo/atomic-react), or execute this command in the terminal: `npm view @coveo/atomic | grep alpha`. . Run `npm install`. > **Note** > > If the installation fails due to some dependencies requiring a more recent version of React, run the following command to upgrade React to that version. > For example, if `React@>=18.0.0` is required, run: > > ```bash npm install react@18.0.0 react-dom@18.0.0 --legacy-peer-deps ``` . Once all dependencies are installed, move the Atomic localization files to the `static` folder: ```bash cp -r node_modules/@coveo/atomic-react/dist/lang app/static ``` . To adjust the server side rendering (SSR), open the `app/ssr.js` file and edit the `handler` function: .. Find the directives section and add the following: ```bash 'connect-src': ["'self'", "'unsafe-eval'", 'analytics.cloud.coveo.com', 'platform.cloud.coveo.com', 'storage.googleapis.com'] ``` .. Add a route for the default localization file: ```bash app.get('/lang/en.json', runtime.serveStaticFile('static/lang/en.json')) ``` . To replace the default search, edit the `app/routes.jsx` file. .. In the `Pages` section, add a new constant: ```javascript const CoveoSearch = loadable(() => import('./pages/coveo-search'), {fallback}); ``` .. In the `Routes` array, find the `/search` route and replace it with the following: ```javascript { path: '/search', component: CoveoSearch }, ``` ## Build a search UI For its layouts, the Composable Storefront uses the [Chakra UI framework](https://chakra-ui.com/). Combine the Chakra UI tags with the Atomic elements as shown in the code below. . Create a `pages/coveo-search/index.jsx` file and paste the following code into it: ```javascript import React from "react"; import PropTypes from "prop-types"; import { loadFieldActions, loadQueryActions, loadSearchActions, loadSearchAnalyticsActions } from "@coveo/headless"; import { AtomicResultList } from "@coveo/atomic-react"; <1> import { Box, Grid, Stack, Flex, useMultiStyleConfig, AspectRatio, Text, Link } from "@chakra-ui/react"; import DynamicImage from "../../components/dynamic-image"; import { useIntl } from "react-intl"; import { productUrlBuilder } from "../../utils/url"; const CoveoSearch = () => { const intl = useIntl(); const styles = useMultiStyleConfig("ProductTile"); return ( <> <2> ( <> {/* Title */} {r.raw.ec_name} {/* Price */} { r.raw.ec_price } )} /> ); }; CoveoSearch.getTemplateName = () => "coveo-search"; CoveoSearch.shouldGetProps = ({ previousLocation, location }) => !previousLocation || previousLocation.pathname !== location.pathname || previousLocation.search !== location.search; CoveoSearch.getProps = async ({ engine, location }) => { const searchInterface = document.querySelector("atomic-search-interface"); const urlParams = new URLSearchParams(location.search); let searchQuery = urlParams.get("q"); const newProps = { searchQuery }; if (!engine) { const configuration = { accessToken: "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", organizationId: "orgnameplaceholder" }; <3> await searchInterface.initialize(configuration); newProps.engine = engine = searchInterface.engine; const fieldActions = loadFieldActions(engine); engine.dispatch(fieldActions.registerFieldsToInclude( `ec_name, ec_price, ec_images, ec_productid, sf_c_currency, sf_c_image, sf_c_price, title, uri`.split(","))); } <4> // execute search const searchActions = loadSearchActions(engine); const queryActions = loadQueryActions(engine); const analyticsActions = loadSearchAnalyticsActions(engine); await engine.dispatch(queryActions.updateQuery({ q: searchQuery || "test" })); const searchResults = await engine.dispatch(searchActions.executeSearch(analyticsActions.logSearchboxSubmit())); newProps.searchResults = searchResults; return newProps; }; CoveoSearch.propTypes = { engine: PropTypes.object, isLoading: PropTypes.bool, location: PropTypes.object, searchQuery: PropTypes.string, }; export default CoveoSearch; ``` <1> Imports one component from the `atomic-react` package. Use as many components from this package as you want and combine them with pure HTML Atomic tags. <2> Mounts the default Atomic theme. Learn more about Atomic customization in [Themes and visual customization](https://docs.coveo.com/en/atomic/latest/usage/themes-and-visual-customization/). <3> Specifies credentials for the target Coveo organization. See [API key](https://docs.coveo.com/en/105/) and [search token](https://docs.coveo.com/en/56/) authentication. <4> Retrieves the specified fields from the Coveo organization. These fields are used throughout the UI layout, for example, in facets. > **Important** > > To see the search results, make sure that your Coveo organization already has [data indexed from a Salesforce Commerce Cloud instance](https://docs.coveo.com/en/sal3s118/). . To launch the application locally, run the `npm start` command. The application will open in the browser, at the `+http://localhost:3000+` address by default. . In the upper-right corner, you can see the search bar. Try to type in "dress" or "shirt" and then select Enter to see the search results powered by Coveo.