Purpose of a Standalone Search Box
When you utilize Coveo and build custom interfaces one thing that will stand out is that of the Search Box. In particular, the fact there are two ways of implementing a search box. A normal search box that's included within a search page and that of a standalone version.
The main difference is that the Standalone version is fully independent and doesn't interact directly with things like results and facets. Its sole purpose is to take in a search query, present potential Query Suggestions (if applicable), and the redirect the query to the search result page.
In a Headless environment, this is achieved using local storage to store the query-related information before it's redirected to the search results. The Standalone Search Box effectively never executes a search query.
Let's Build It
The first thing to do is to set up the initialization of the Standalone Search Box. There aren't many options, but you can find the full list here: StandaloneSearchBoxOptions.
We won't be going into how to display Query Suggestions this time around but hope to in a future article.
Setup Search Box Initialization
The initialization of the standalone search box is relatively clean and simple. We use the HeadlessEngineContext we created previously. Once done, we pass the controller
we obtained from buildStandaloneSearchBox
to our renderer function. You could very well combine these two if so desired.
const StandaloneSearchBox = (props: any) => {
const options: StandaloneSearchBoxOptions = {
numberOfSuggestions: props.numOfPages,
redirectionUrl: props.searchPage,
};
const engine = useContext(HeadlessEngineContext) as unknown as SearchEngine;
const controller = buildStandaloneSearchBox(engine, { options });
return (
<SearchBoxRenderer
engine={engine}
controller={controller}
searchPage={props.searchPage as string}
/>
);
};
Setup Renderer Function
As part of the renderer, we've added two buttons that assist with both the submission as well as the clearing of the query. For those we've used react-feather
to display the icons.
Within the if statement for redirectTo
, if true
, we store the query value and analytics into local storage to be read by the result page.
interface StandaloneSearchBoxProps {
engine: SearchEngine;
controller: HeadlessSearchBox;
searchPage: string;
}
const SearchBoxRenderer: FunctionComponent<StandaloneSearchBoxProps> = (props) => {
const { controller } = props;
const [state, setState] = useState(controller.state);
// Ensure we detect users who hit Enter key.
const isEnterKey = (e: React.KeyboardEvent<HTMLInputElement>) => e.key === 'Enter';
// Need function when a query is Submitted.
const submitQuery = (): void => {
if (!state) {
return;
}
const { redirectTo, value, analytics } = state;
// If there is a redirectTo value, this indicates we want to send the user to the result page.
if (redirectTo) {
const data = { value, analytics };
localStorage.setItem('coveo_standalone_search_box_data', JSON.stringify(data));
window.location.href = state.redirectTo;
return;
}
};
// What to do when user clicks to clear query.
const clearQuery = (): void => {
if (!state) {
return;
}
controller.updateText('');
};
submitQuery();
useEffect(() => controller.subscribe(() => setState(controller.state)), []);
return (
<div>
<input
type={'text'}
value={state.value}
onChange={(e) => {
controller.updateText(e.target.value);
showQuerySummary(e.target.value);
}}
onKeyDown={(e) => isEnterKey(e) && controller.submit()}
className={props.searchBoxStyling.inputField}
/>
<div
id={'search-icon'}
onClick={() => submitQuery()}
tabIndex={0}
onKeyPress={(e) => (e.key === 'Enter' ? submitQuery() : null)}
>
<Search />
</div>
<div
id={'cancel-search-icon'}
onClick={() => clearQuery()}
tabIndex={0}
onKeyPress={(e) => (e.key === 'Enter' ? clearQuery() : null)}
>
<X />
</div>
</div>
);
};
Within the returned DOM we have an input box, a search button, and a clear button. Each has appropriate onChange
, onClick
, or onKeyPress
events that trigger the appropriate responses.
As I mentioned above, this is a very simple Standalone Search Box. You can of course expand upon it to display results from the Query Suggestion model if it's being utilized.