JavaScript Search Framework Result Templates

Result templates determine the format of the individual query results in a search interface. They’re embedded within a specific result layout, and a given template can only apply when its parent layout is selected.

When a query is successful, each result is rendered according to the first template whose condition is satisfied by that result.

Using the Prebuilt Templates

The JavaScript Search Framework includes several prebuilt result templates for common content types (e.g., Salesforce, Jira, Khoros Community). You can use these templates in your search interface by including the templates.js script after the framework script:

<script class="coveo-script" src="https://static.cloud.coveo.com/searchui/v2.9159/js/CoveoJsSearch.Lazy.min.js"></script>
<!-- ... -->
<script src="https://static.cloud.coveo.com/searchui/v2.9159/js/templates/templates.js"></script>

Registering Your Own Templates

You can register custom result templates instead of using the prebuilt ones.

To register a custom template for a given result layout, you must embed a script tag in that layout (i.e., in the corresponding ResultList component).

The script tag must have the class="result-template" attribute and a type attribute that specifies which template engine to use. Each custom template1 that’s registered within a given ResultList should also have a unique condition.

<div class="CoveoResultList" layout="list">
  <script id="myPDFResultTemplate" class="result-template"
          type="text/html" data-field-filetype="pdf">
    <!-- ... -->
  </script>
</div>
<div class="CoveoResultList" layout="card">
  <script id="myVideoResultTemplate" class="result-template"
          type="text/html" data-field-filetype="video">
    <!-- ... -->
  </script>
</div>
<div class="CoveoResultList" layout="table">
  <script id="myDocumentResultTemplate" class="result-template"
          type="text/html" data-field-filetype="doc">
    <!-- ... -->
  </script>
</div>

1: With the possible exception of the default template.

Designing a Template

The JavaScript Search Framework supports two template engines along with built-in styling classes, components, and helpers, allowing you to conveniently design your own templates for the various result layouts that are available in a search interface.

Simple HTML list result template example

Choosing a Template Engine

Result templates can use either the HTML engine (recommended) or the Underscore engine. You specify the template engine in the template script tag (i.e., type="text/html" or type="text/underscore").

The HTML and Underscore engines both support JavaScript Search Framework result template components. If your use case is fulfilled by a preexisting component, you should use it instead of implementing your own custom component or using inline JavaScript.

HTML result templates are entirely based on JavaScript Search Framework result template components. They can be executed inside environments with strict content security policies (e.g., Salesforce with Lightning Locker enabled).

<script id="myTemplate" class="result-template"
        type="text/html">
  <div class="coveo-result-frame">
    <div class="coveo-result-row">
      <div class="coveo-result-cell"
           style="<!-- ...some styling... -->">
        <span class="CoveoIcon"></span>
        <div class="CoveoQuickview"></div>
      </div>
      <div class="coveo-result-cell"
           style="padding-left:15px;">
        <div class="coveo-result-row">
          <div class="coveo-result-cell">
            <a class="CoveoResultLink"
               style="font-size:18px;"></a>
          </div>
          <div class="coveo-result-cell"
               style="<!-- ...some styling... -->">
            <span class="CoveoFieldValue"
                  data-field="@date"
                  data-helper="date"></span>
          </div>
        </div>
      </div>
    </div>
  </div>
</script>

If needed, you can expand the capabilities of HTML templates by developing your own custom components.

Using the Underscore Engine

Underscore result templates are extremely flexible because they can execute arbitrary JavaScript code. However, they may not be compatible with, or secure enough for, strict content security policies or setups (e.g., Salesforce with Lightning Locker enabled). Moreover, Underscore templates can become hard to read and difficult to maintain.

<script id="myTemplate" class="result-template"
        type="text/underscore">
  // Use a Coveo helper to format the date and time,
  // referencing the raw.sysdate property of each result.
  <div class="my-date"><%= dateTime(raw.sysdate) %></div>
  // Output the excerpt of the result in a div.
  <div class="my-excerpt"><%= excerpt %></div>
</script>

Instead of using Underscore templates, consider using HTML templates and developing your own custom components.

While reading the Underscore template engine documentation, you may notice that you can modify the delimiters (<% %>) by changing the _.templateSettings object.

However, changing these delimiters can cause issues with the JavaScript Search Framework, as they’re used internally. The JavaScript Search Framework offers alternative delimiters ({{ }}), which work the same way as the default delimiters.

This can also be useful when using the JavaScript Search Framework with certain other technologies, such as ASP.NET or JSP, which use the <% %> characters to let the server interpret expressions.

Creating a List Layout Template

This is the default layout for search results. When creating a custom result template, we recommend that you use the standard styling classes to organize your template into a grid.

List result template example

Your template will include a number of result template components. The JavaScript Search Framework offers a variety of standard components, and you can also develop your own custom components if needed.

<div class="CoveoResultList" layout="list">
  <script id="myListTemplate" class="result-template"
          type="text/html" data-layout="list">
    <div class="coveo-result-frame">
      <div class="coveo-result-cell"
           style="<!-- ...some styling... -->">
        <span class="CoveoIcon" data-small="true"
              data-with-label="false"></span>
        <div class="CoveoQuickview"></div>
      </div>
      <div class="coveo-result-cell"
           style="<!-- ...some styling... -->">
        <div class="coveo-result-row"
             style="margin-top:0;">
          <div class="coveo-result-cell"
               style="<!-- ...some styling... -->">
            <a class="CoveoResultLink"></a>
          </div>
          <div class="coveo-result-cell"
               style="<!-- ...some styling... -->">
            <div class="coveo-result-row">
              <span class="CoveoFieldValue"
                    data-field="@date"
                    data-helper="date"></span>
            </div>
          </div>
        </div>
        <div class="coveo-result-row"
             style="margin-top:10px;">
          <div class="coveo-result-cell">
            <span class="CoveoExcerpt"></span>
          </div>
        </div>
        <div class="coveo-result-row"
             style="margin-top:10px;">
          <div class="coveo-result-cell">
            <span class="CoveoFieldValue"
                  data-field="@author"
                  data-text-caption="Author"
                  style="margin-right:30px;"></span>
            <span class="CoveoFieldValue"
                  data-field="@source"
                  data-text-caption="Source"
                  style="margin-right:30px;"></span>
            <span class="CoveoFieldValue"
                  data-field="@language"
                  data-text-caption="Language"
                  style="margin-right:30px;"></span>
            <span class="CoveoFieldValue"
                  data-field="@filetype"
                  data-text-caption="File Type"
                  style="margin-right:30px;"></span>
          </div>
        </div>
        <div class="coveo-result-row"
             style="margin-top:10px;">
          <div class="coveo-result-cell">
            <div class="CoveoPrintableUri"></div>
          </div>
        </div>
        <div class="coveo-result-row">
          <div class="coveo-result-cell">
            <div class="CoveoMissingTerms"></div>
          </div>
        </div>
      </div>
    </div>
  </script>
</div>

Creating a Card Layout Template

The JavaScript Search Framework offers two card layout-specific components that you can only use in Card layout result templates:

Using the CardActionBar Component

The CardActionBar component renders a bar at the bottom of a card. Its primary use is to display action buttons for the result in which it embeds itself.

CardActionBar component

To add a CardActionBar, insert the component as the last element in a coveo-result-frame element.

<div class="CoveoResultList" data-layout="card">
  <script id="myCardTemplate" class="result-template"
          type="text/html">
    <div class="coveo-result-frame">
      <!-- ... -->
      <div class="CoveoCardActionBar">
        <div class="CoveoQuickview"></div>
        <div class="my-custom-button"
             onclick="alert('Hello, world!')">Click me!</div>
      </div>
    </div>
  </script>
</div>

The prebuilt Card templates all feature the CardActionBar component, which they usually populate with a Quickview button and a CardOverlay component.

Using the CardOverlay Component

The CardOverlay component should be used inside the CardActionBar component. It displays complementary information about a result.

CardOverlay component

The CardOverlay component works by :

  1. Finding all of its child DOM nodes.

  2. Creating a hidden overlay containing these nodes.

  3. Displaying a toggle button to show the overlay.

<div class="CoveoResultList" data-layout="card">
  <script id="myCardTemplate" class="result-template"
          type="text/html">
    <div class="coveo-result-frame">
      <!-- ... -->
      <div class="CoveoCardActionBar">
        <div class="CoveoQuickview"></div>
        <div class="CoveoCardOverlay" data-title="Open me"
             data-icon="replies">
          <!-- ...overlay content... -->
          <div class="CoveoText"
               data-value="Here is some additional info."
               style="margin:5px;"></div>
        </div>
      </div>
    </div>
  </script>
</div>

When the end user opens or closes the CardOverlay component, it triggers an openCardOverlay or closeCardOverlay event, which you can bind to any handler. This is useful if you only want to execute actions when the end user opens or closes the overlay.1

1: For example, the ResultFolding component uses the openCardOverlay event to fetch additional results when the end user opens the overlay.

Creating a Table Layout Template

The JavaScript Search Framework allows you to customize the header and footer of your table using the role option.

Table layout result template

To specify a role, add a data-role="table-header" or data-role="table-footer" attribute to the script tag of your result template.

<div class="CoveoResultList" data-layout="table">
  <script id="myTableHeader" class="result-template"
          type="text/html" data-role="table-header">
    // Any styling you add to the header
    // affects the rest of the table.
    <th style="width:40%;">Link</th>
    <th>Description</th>
    <th>URL</th>
    <th style="width:20%;"
        class="CoveoSort coveo-table-header-sort"
        data-sort-criteria="date ascending,date descending"
        data-display-unselected-icon="false"
        data-caption="Date"></th>
  </script>
  // Because this template has no `data-role` attribute,
  // it applies to each table row for your results.
  <script id="myTableTemplate" class="result-template"
          type="text/html">
    <td><a class="CoveoResultLink"></a></td>
    <td><span class="CoveoExcerpt"></span></td>
    <td><span class="CoveoFieldValue"
              data-field="@uri"></span></td>
    <td><span class="CoveoFieldValue"
              data-field="@date"
              data-helper="date"></span></td>
  </script>
  // You can also add a template
  // whose `data-role` is `table-footer`.
</div>

By default, table headers and footers behave as follows:

  • If you don’t register any custom templates, the prebuilt Table template displays a table header with the default fields (i.e., Result Link, Excerpt, and Date).

  • If you register a custom Table template but don’t register a separate table header template, the table header is hidden.

  • By default, the table footer is hidden.

  • If you register a custom table footer template, the table footer is displayed.

Assigning Conditions to Your Templates

Whenever a query result must be rendered, the JavaScript Search Framework uses its condition evaluation mechanism to determine which result template to use. Each template should have a unique condition that can only be satisfied by the desired subset of results.

A condition can either be field-based (recommended) or written in JavaScript.

Understanding the Condition Evaluation Mechanism

For each query result, the custom result templates embedded inside the selected result layout (i.e., in the selected ResultList component) are evaluated in the order in which they appear in the markup. The first template whose condition is satisfied by the result applies.

If a result satisfies none of the custom template conditions, and if the prebuilt result templates are available, then the prebuilt templates are also evaluated until the query result satisfies a condition.

You can define a field-based condition by adding one or more data-field-<NAME> attributes to the script tag of a custom result template, where you replace <NAME> with the name of the field on which you want to base the condition clause (e.g., data-field-filetype).

<div class="CoveoResultList" data-layout="list">
  // If @filetype is "video":
  <script id="myVideoResultTemplate" class="result-template"
          type="text/html" data-field-filetype="video">
    <!-- ... -->
  </script>
  // Else if @filetype is "doc" OR @filetype is "pdf":
  <script id="myDocumentResultTemplate" class="result-template"
          type="text/html" data-field-filetype="doc,pdf">
    <!-- ... -->
  </script>
  // Else if @sfid contains any non-null value:
  <script id="mySFIDResultTemplate" class="result-template"
          type="text/html" data-field-sfid>
    <!-- ... -->
  </script>
  // Else if @filetype is "html" AND @source is "mysource":
  <script id="myHTMLResultTemplate" class="result-template"
          type="text/html" data-field-filetype="html"
          data-field-source="mySource">
    <!-- ... -->
  </script>
  <!-- ...more result templates... -->
</div>

These conditions behave as follows:

  • In a single field-based clause with multiple values (e.g., data-field-filetype="doc,pdf"), commas are interpreted as logical OR operators.

  • A field-based clause with no specified values (e.g., data-field-sfid) is interpreted as a non-null check against the target field.

  • Distinct field-based clauses on the same template are joined with the AND logical operator.

Field-based conditions can be executed inside environments with strict content security policies (e.g., Salesforce with Lightning Locker enabled), and they’re not likely to result in unrecoverable configuration errors.

Using JavaScript Conditions

You can define a JavaScript condition by adding a data-condition attribute to the script tag of a custom result template.

Most conditions rely on field values. These are accessible from the raw property of the current query result (e.g., raw.filetype).

<div class="CoveoResultList" data-layout="list">
  // If @filetype is "image":
  <script id="myImageResultTemplate" class="result-template"
          type="text/html" data-condition="raw.filetype=='image'">
    <!-- ... -->
  </script>
  // Else if @price is larger than 500:
  <script id="myPriceResultTemplate" class="result-template"
          type="text/html" data-condition="raw.price>500">
    <!-- ... -->
  </script>
  <!-- ...more result templates... -->
</div>

JavaScript conditions are highly flexible, as they can evaluate arbitrary Boolean expressions. However, they may not be compatible with, or secure enough for, strict content security policies or setups (e.g., Salesforce with Lightning Locker enabled).

These conditions can also make it more difficult to detect faulty logic, as there’s a greater margin for configuration errors. Moreover, it’s possible to configure JavaScript conditions with invalid syntax, which would prevent results from rendering.

Defining a Default Result Template

A result template with no condition will always apply if it’s evaluated. You can use such a template as the default one for a given result layout by embedding it last within the desired ResultList.

<div class="CoveoResultList" data-layout="list">
  <script id="myVideoResultTemplate" class="result-template"
          type="text/html" data-field-filetype="video">
    <!-- ... -->
  </script>
  <script id="myPDFResultTemplate" class="result-template"
          type="text/html" data-field-filetype="pdf">
    <!-- ... -->
  </script>
  <!-- ...more result templates with conditions... -->
  <script id="myDefaultResultTemplate" class="result-template"
          type="text/html">
    <!-- ... -->
  </script>
</div>

Since the JavaScript Search Framework evaluates custom templates before the prebuilt ones, including a custom template with no condition in a ResultList implies that the prebuilt templates will never apply for that layout.

Reference

Result Template Components

You can use result template components to customize how your results are displayed in your search interface.

The generated reference documentation for all publicly exposed components is available on GitHub.

To insert a component, add a div element with the Coveo<COMPONENT> class inside your template, where you replace <COMPONENT> with the name of the component that you want to insert (e.g., class="CoveoSort").

You must then define all of the required and/or desired options for that component by adding one or more data-<OPTION> attributes to this element, where you replace <OPTION> with the name of the option that you want to set (e.g., data-sort-criteria to set the sortCriteria option for the Sort component).

Sample Component Use Case

You want to add the Quickview component to your result template, and you always want the Quickview button to be visible, even if the body of an item is empty (i.e., using the alwaysShow option).

Inside the script element of your result template, add the following line:

<div class="CoveoQuickview" data-always-show='true'></div>

Generic Component List

Backdrop

Coveo JavaScript Search Framework 1.2126.4 (February 2017)

Renders a background image. This is useful for displaying information on top of a dynamic background in a card result.

Badge

Outputs a field value that’s displayed as a colored badge. This component inherits from the FieldValue component.

Excerpt

Outputs an excerpt of the result with the keywords highlighted.

FieldTable

Displays a table with one or more FieldValue components.

FieldValue

Outputs a clickable field value that can add a filter in queries.

FollowItem

Allows the end user to follow a particular item so that they receive email notifications whenever the item changes.

Icon

Outputs an icon related to the result type.

ImageFieldValue

Coveo JavaScript Search Framework 2.7023 (September 2019)

Renders an img HTML tag from a field whose value points to the URL of an image file.

MissingTerms

Coveo JavaScript Search Framework 2.6459 (July 2019)

Renders a list of query terms that were not matched by the result item.

PrintableUri

Outputs the printable (or breadcrumb) URI for a result.

Quickview

Outputs the clickable Quickview icon, which opens a modal window. This usually references a QuickviewDocument component in its content template.

ResultActionsMenu

Coveo JavaScript Search Framework 2.4382.10 (July 2018)

Adds a floating menu which may contain components to execute actions related to the result (e.g., Quickview).

ResultAttachments

Allows you to display the attachments for a result, given that a Folding component is present in the page and properly configured.

ResultFolding

Allows you to display folded results, given that a FoldingForThread or Folding component is present in the page and properly configured.

Transforms search result titles into clickable links that log usage analytics events.

StarRating

Coveo JavaScript Search Framework 2.7968.7 (January 2020)

Renders a five-star rating widget for use in commerce result templates.

Text

Embeds itself in a result template to output a simple text value. This is only useful in the Interface Editor.

Thumbnail

Automatically fetches the thumbnail of the result object and outputs an HTML img tag from it.

YouTubeThumbnail

Automatically fetches the thumbnail of a YouTube video and outputs a clickable HTML img tag from it.

Card Layout-Specific Component List

CardActionBar

Coveo JavaScript Search Framework 1.2126.4 (February 2017)

Displays an action bar at the bottom of a card result.

CardOverlay

Coveo JavaScript Search Framework 1.2126.4 (February 2017)

Displays a button that the end user can click to toggle the visibility of an overlay on top of the result.

Deprecated Component List

ResultRating

Enables the collaborative rating of items, based on a 5-star rating system.

ResultTagging

Allows end users to tag items, if tagging is enabled for your index.

Result Template Helpers

When using a FieldValue component, you can use result template helpers to modify the way in which field values are displayed.

If the prebuilt helpers don’t meet your needs, you may want to create your own.

Helpers can be used with both the HTML and Underscore engines.

Sample Helper Use Case

You want to display the value of the @edition field in your result template, but you know that its value can be long. To ensure that it doesn’t exceed 30 characters when presented in the template, you decide to use the shorten helper function.

  • Using an HTML template:
<div class="CoveoFieldValue"
     data-field="@edition"
     data-helper="shorten"
     data-helper-options-length="30">
</div>
  • Using an Underscore template:
<%= shorten(edition, 30) %>

Result Template Styling Classes

Coveo offers the following CSS classes for result templates:

  • coveo-result-frame

  • coveo-result-row

  • coveo-result-cell

Typically, result frames contain result rows, which contain result cells, which in turn contain result template components. Result cells can also contain their own result rows, which can then contain other result cells, and so on.

Result template CSS classes

Template Styling Tips

  • Add the CSS classes to simple div elements.

  • Only insert one coveo-result-frame element per result template. This frame should include all of the other elements of your result template.

  • Use coveo-result-row elements inside of your coveo-result-frame to separate the components into rows.

  • Include one or more coveo-result-cell elements inside each coveo-result-row.

  • Insert result template components inside of the coveo-result-cell elements. You can use multiple components in the same cell.

  • Optionally, you can add further coveo-result-row elements inside of a coveo-result-cell.

  • Optionally, you can add inline styling or special CSS classes that set the width or alignment of your result cells. You can also add CSS classes of your own and add additional styling rules.

What’s Next?

Learn more about designing templates:

Recommended Articles