Templating in Zoovu Search
Option 2: Using templates for custom result cards
If the default card structure does not meet your needs, you can fully customize the search result card layout using templates.
How templating works:
- Choose the most complex product card from your site as a reference.
- Format the HTML and replace specific data (e.g., product title, price) with placeholders.
- Use template variables to dynamically insert data.
Templating lets you create a custom HTML structure for search suggestions and results. This helps you match the Zoovu Search JS plugin to your site's design while giving you more control over the layout.
Using custom templates only modifies the markup of search results and suggestions. Other settings, such as grid layout and tabbed navigation, remain unchanged.
Configuring templating
To enable templating, add a configuration object to the block of your zoovuSearchConfig
:
suggestTemplate
(for search suggestions)resultTemplate
(for search results)
Version requirements:
- Search result templates require Zoovu Search plugin v12.3.1+.
- Search suggestion templates require v13.1.1+.
Configuration object structure
Property | Description |
---|---|
template | The HTML template string. |
preRenderCallback | Called before the result is built. |
templateBuiltCallback | Called after the result is built but before it's converted to a DOM node. |
postRenderCallback | Called after the DOM node is created. |
variableReplacementPattern | Regex pattern to remove matching text before creating a DOM node. |
dataPointDefaults | Defines default values for missing data points. Example: {isNew: false} . |
Templating rules
Zoovu's templating syntax is similar to the Mustache templating engine. Each search result or suggestion includes properties you can use in the template:
Property | Description |
---|---|
name | The result title. |
image | The result image URL. |
link | The result URL. |
content | The result snippet (only for search results). |
images | Alternative images (array of { "type": "alternative", "url": "<image_url>" } ). |
dataPoints | An array of data points: { "key": "Data Point Name", "value": "Data Point Value", "show": true } . |
dataPointHash | A mapping of data point keys to values. |
attributes | A mapping of concept identifiers to values (e-commerce only, v15 and later). All spaces in concept identifiers are replaced with an underscore. |
highlightedName | The result title with highlighted query terms (for search suggestions). |
variants | An array of product variants (e-commerce only). |
isResultTypeCustom | Boolean indicating if the result has custom HTML. |
Injecting content:
- Use
{{variableName}}
to insert content (HTML characters will be escaped). - Use
{{{variableName}}}
to insert raw HTML.
Example:
<div class="result">
<h3 class="result__title">{{name}}</h3>
<a class="result__link" href="{{link}}">See more</a>
<p class="result__snippet">{{{content}}}</p>
</div>
Use {{#array}}...{{/array}}
to loop through an array.
Example: Displaying all data point values
<ul class="result__datapoints">
{{#dataPoints}}
<li class="result__datapoint"><strong>{{key}}:</strong> {{value}}</li>
{{/dataPoints}}
</ul>
Conditional rendering:
Show content only if a condition is met:
{{#condition}}I am true{{/condition}}
Show content if a condition is false:
{{!#condition}}I am false{{/condition}}
Example:
<div class="result {{#image : "result--has-img" #}}">
<h2>{{name}}</h2>
<p>
{{#link}}
<a href="{{link}}">Here you go</a>
{{/link}}
{{!#link}}
Sorry, we can't take you to the search result.
{{/link}}
</p>
</div>
Accessing specific array elements
- Use
{{array[0]}}
to get the first item. - Use
{{object.property}}
to get a property from an object. - Combine both to query an array value of an object:
{{dataPointHash.price[0]}}
or{{attributes.PRICE[0]}}
.
Callbacks
Callbacks let you customize templates before, during, and after rendering.
preRenderCallback
- Called before the template is processed.
Arguments:
suggest
(Object): The full search result/suggestion.globalStore
(Object): Shared storage for all results.contentGroup
(String): The content group name.
templateBuiltCallback
- Called after applying templating rules but before creating a DOM node.
Arguments:
template
(String): The processed template string.suggest
,globalStore
,contentGroup
: Same as preRenderCallback.
Example: Modifying template text
function(template, suggest) {
return template.replace("Old Text", "New Text");
}
postRenderCallback
- Called after creating the DOM node.
Arguments:
node
(Node): The generated DOM node.suggest
,globalStore
,contentGroup
: Same as above.
Example: Adding an event listener
function(node) {
node.addEventListener("click", () => {
console.log("Search result clicked!");
});
}
Tips & tricks
Highlighting custom templates
Default hover/keyboard selection highlighting won’t work.
Add unibox__highlight-container
to apply a grey background when selected.
Or use custom CSS:
.unibox__selectable--active, .unibox__selectable:hover {
background-color: lightgray;
}
Using a <template>
tag for large templates
Instead of storing large templates in JavaScript, use an HTML <template>
:
<template id="zoovu-result-template">
<div class="my-search-result">
<!-- Template Code -->
</div>
</template>
<script>
var zoovuSearchConfig = {
results: {
resultTemplate: {
template: document.getElementById("zoovu-result-template").innerHTML
}
}
}
</script>
Example: Implementing result and suggestion templates
var zoovuSearchConfig = {
results: {
resultTemplate: {
template: '<article class="my-search-result"><h2>{{name}}</h2></article>'
}
},
suggestions: {
suggestTemplate: {
template: '<article class="my-search-suggestion"><h3>{{name}}</h3></article>'
}
}
}