Customizing Coveo Atomic with Headless
Coveo Atomic is great. It lets you make an entire search page extremely quickly, with good out-of-the box-styling, accessibility, and well done UI. You can build out your results to look however you like, add filters in moments, and so on.
That’s great, no questions asked. There might be things you want to customize or special use cases that you need, though. For those, you can reach down into the underlying technology, Coveo Headless. Coveo atomic is a wonderful presentation layer that’s built on top of Headless, and every little widget and setting is accessible if you need or want to change it.
The Coveo Headless Setup
The basic method is fairly simple. You find the headless component you want, and import it into the top of your Atomic javascript. Like so:
import { buildFacet } from 'https://static.cloud.coveo.com/atomic/v2/headless/headless.esm.js';
In this case, we’re using a facet as the example. The most important point here is that “buildFacet” doesn’t build the facet again. You can think of it as locating the facets you’ve already got, or building a controller to access them. This applies to all of the various components.
You can see the list of atomic components here and the corresponding headless components here.
How to Use the Coveo Headless Component
After we’ve imported the component we want, then we build the controller to use it.
First, we need the headless “engine” to bind the controller too.
const engine = searchInterface.engine;
const facetController = buildFacet(engine, { options:
{ facetId: "locationFacet", field: "location" }
});
Then we use the engine, and an options object to instantiate the controller. The facet controller needs to know which ID and which field to bind to. We need the options object or the controller will look for all the potential arguments instead of using the default values.
Our facet looks like this:
<atomic-facet
facet-id="locationFacet"
field="location"
label="Location"
sort-criteria="occurrences"
with-search="false"
>
</atomic-facet>
For simplicity’s sake, we’re going to say our search page is has a special section where the logo of each location is shown. When the user changes the facet value, a new location shows up. The various null checks have been left out for brevity.
facetController.subscribe(() => {
const state = facetController.state;
const val = state?.values?[0]; //for example, assume the values are sorted with the selected one first
if(val.value && val.state==='selected'){
ShowLocation(val.value);
} else {
//the facet is blank
ShowDefaultLocation();
}
});
The ShowLocation and ShowDefaultLocation methods are up to you. A potential improvement is searching the values for the selected value, too.
That’s the End!
That’s all you need. Any of the components can be used this way, like buildRedirectController or even buildFacetManager if you want to add new facets on the fly.