Skip to main content

Templates

Templating can be used to define a custom HTML structure for your search suggestions and results.

This lets you integrate the Site Search 360 JS plugin closely with your site's theme and makes layout customization even more flexible.

Defining custom templates will only override the search suggestion/result markup without having an impact on most of the plugin settings (e.g. grid layout or tabbed navigation).

Configuration

To configure templating you need to add a configuration object to the suggestions (suggestTemplate property) or results (resultTemplate property) block of your ss360Config.

The configuration object for search suggestions and search results has the same structure and looks as follows:

  • template is the HTML template string.
  • preRenderCallback is called before the template string is processed.
  • templateBuiltCallback is called after the template is built (all templating rules applied) but before it is converted to a DOM node.
  • postRenderCallback is called after the DOM node has been created.
  • variableReplacementPattern is a regex pattern, everything matching this pattern will be replaced with an empty string before a DOM node is created.
  • dataPointDefaults is an object mapping of data point names to default values. Every search result missing a data point given in this property will be assigned a new data point containing the default value (e.g. {isNew: false}).
  • includeContentGroups is an array of content group names. When set, the template is applied only to results whose content group is in the list; results in other content groups use the default renderer. When omitted, the template applies to all content groups. Available for both result and suggestion templates.
  • highlightContext is a CSS selector that controls which elements inside each result the matched query terms are highlighted in. When omitted, the default selector .ss360-suggests__content > p, .ss360-suggests header a is used (the class prefix matches your configured CSS prefix). This property applies to the result template only — search suggestions use their own highlighting.

The three callbacks (preRenderCallback, templateBuiltCallback, postRenderCallback) are documented in detail under Template callbacks below. For plugin-level callbacks such as preSearch, postSearch, or preRender, see the Callbacks & Hooks article.

To use custom search result templates, you need to run at least version 12.3.1 of the plugin, and to use custom search suggestion templates - version 13.1.1 and later.


Templating rules

To fill in your HTML template with content, you can use syntax similar to the Mustache templating engine. The render context is always a single search result/suggestion with the following properties:

  • name - the result title.
  • image - the result image url.
  • link - the result url.
  • content - the search result snippet (this property is not set for search suggestions).
  • images - an array containing the URLs of the alternative images for the result. Each element has the following structure: { "type": "alternative", "url": "https://link-to-the-result-image.jpg" }. The first element, images[0].url, is (normally) the same as image.
  • dataPoints - an array of data points, each data point has the following structure: {"key": "Data Point Name", "value": "Data Point Value", "show": true}
  • dataPointHash - an object mapping data point keys (camelcase) to an array of data point 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. This property is only available for search suggestions. The highlighted query terms can be styled by using the unibox__highlight class name (e.g. .unibox__highlight { font-weight: 700 }.
  • variants - an array of all available product variants (ecommerce only). The name , image, link, content, images, and dataPoints properties are available within a single variant object.
  • isResultTypeCustom - a boolean indicating whether a single result is a custom result (provides custom html that should be rendered).

To inject content into the HTML template you can use the {{variableName}} rule. This will lead to all special HTML characters to be escaped. If you do want to inject the HTML content into your template without escaping special characters, you can use the {{{variableName}}} rule.

Undefined properties will be replaced with an empty string.

<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>

If the target property is an array, you can use loops (the {{#array}}{{item}}{{/array}} rule) to iterate over every item, which will become the new render context (use @value to target an element of a string array). This can be useful for displaying all data point values:

<ul class="result__datapoints">
{{#dataPoints}}
<li class="result__datapoint"><strong>{{key}}:</strong> {{value}}</li>
{{/dataPoints}}
</ul>

To render a specific block under a certain condition, you can use the {{#condition}}I am true{{/condition}}> rule. The condition evaluates to false if it is false, undefined, null, or an empty array. To invert conditions, you can use the {{!#condition}}I am false{{/condition}} rule.

Conditional statements can also be inlined directly into an HTML tag: <span class="{{# condition : "condition__true" #}}">Test</span>, or<span class="{{!# condition : "condition__false" #!}}">Test</span>

<div class="result {{# image : "result--has-img" #}}">
&lt;h2&gt;{{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>

To inject content from an array you can directly query a specific index {{array[0]}} (0 based), specific values from object properties can be injected by using {{object.myProperty}}. Both can also be combined to query an array value of an object, e.g. {{dataPointHash.price[0]}} or {{attributes.PRICE[0]}}.


Template callbacks

The template configuration accepts three optional callbacks that let you hook into a single result or suggestion as it is built and rendered. They are template-scoped — each receives the current suggest object, a shared globalStore, and the contentGroup name — which makes them different from the plugin-level callbacks in Callbacks & Hooks.

Both resultTemplate and suggestTemplate accept the same callbacks. They fire in this order:

  1. preRenderCallback — before the template string is processed.
  2. templateBuiltCallback — after the template is built, before it becomes a DOM node.
  3. postRenderCallback — after the DOM node has been created.

preRenderCallback

Called before the template string is processed. Modify the suggest object here to set custom properties for interpolation.

Arguments:

  • suggest — (Object) the current result or suggestion. This is the same object whose properties you interpolate in the template — see Templating rules for the available fields. Modifying it here adds or changes properties before interpolation.
  • globalStore — (Object) a store shared across all results and suggestions. Use it for global variables, such as a result counter.
  • contentGroup — (String) the content group name.

templateBuiltCallback

Called after the template is built (all templating rules applied) but before it is converted to a DOM node. Use it for complex replacements on the template string.

Arguments:

  • template — (String) the built template string. Return the modified string.
  • suggest — (Object) the current result or suggestion.
  • globalStore — (Object) the shared store.
  • contentGroup — (String) the content group name.

postRenderCallback

Called after the DOM node has been created. Use it to bind custom events or adjust the rendered element.

Arguments:

  • node — (Object) a wrapped element collection, not a bare DOM node. Access the underlying HTMLElement with node[0].
  • suggest — (Object) the current result or suggestion.
  • globalStore — (Object) the shared store.
  • contentGroup — (String) the content group name.

node is an internal wrapped collection, not a native HTMLElement. Access the real DOM element with node[0].

postRenderCallback: (node, suggest, globalStore, contentGroup) => {
const el = node[0] || node; // unwrap the collection
el.classList.add('my-custom-result');
}

postRenderCallback is valid on both templates at the config level, but the Advanced tab exposes a PostRender field only for the result template. To use it with the suggestions template, set it in your embed config.

Placement

<script>
var ss360Config = {
results: {
resultTemplate: {
template: '<article>{{name}}</article>',
preRenderCallback: (suggest, globalStore, contentGroup) => {},
templateBuiltCallback: (template, suggest, globalStore, contentGroup) => template,
postRenderCallback: (node, suggest, globalStore, contentGroup) => {
const el = node[0] || node; // node is a wrapped collection — unwrap to access the HTMLElement
el.classList.add('my-custom-result');
}
}
},
suggestions: {
suggestTemplate: {
template: '<li>{{name}}</li>',
preRenderCallback: (suggest, globalStore, contentGroup) => {},
templateBuiltCallback: (template, suggest, globalStore, contentGroup) => template
}
}
};
</script>

In the dashboard, a template's callback fields stay greyed out until you enter a template string — a callback that runs before or after the template is built has nothing to act on without a template. Enter a template first, and its callbacks become editable.


Tips & Tricks

The default highlighting of search suggestions (on hover, or keyboard select) won't work for custom templates.

Add the class unibox__highlight-container to the content you want to highlight on selection and it will automatically receive a grey background when selected.

Alternatively, you can use custom CSS to target a selected suggestion by using the following CSS selector: .unibox__selectable--active, .unibox__selectable:hover.

As the ss360Config needs to be a valid JavaScript object, long templates might be difficult to modify. If you don't use string literals and a JS compiler to ensure cross-browser compatibility, you can also put the full template into a <template> tag and read it directly from the DOM:

<!-- ... -->
<template id="ss360-result-template" style="display: none;">
<div class="my-search-result">
<!-- Template Code -->
</div>
</template>
<script>
var ss360Config = {
/* ... configuration ... */
results: {
/* ... result configuration ...*/
resultTemplate: {
template: document.getElementById("ss360-result-template").innerHTML
}
}
}
</script>
<!-- ... -->

Example

Suggestions-templating works almost exactly in the same way as for search results.

This example below shows how results and suggestions templates can be implemented together:

<script>
var ss360Config = {
/* ... configuration ... */
results: {
/* ... result configuration ...*/
resultTemplate: {
template: '<article class="my-search-result">&lt;h2&gt;{{name}}</h2></article>'
}
},
suggestions: {
/* ... suggestions configuration ...*/
suggestTemplate: {
template: '<article class="my-search-suggestion">&lt;h3&gt;{{name}}</h3></article>'
}
}
}
</script>