HTML and EJS reference for Loomi AI for Shopify

Loomi AI for Shopify widgets let you replace their default HTML using Experience customization. This article lists mandatory data attributes, supported EJS variables, and a working example per component.

🛑

Customer responsibility

Custom HTML overrides are the customer's responsibility. Test all customization on your storefront before publishing and verify that they preserve the requirements in this article.

Examples show the structural markup and data hooks — add your own CSS to match your design system.

Access experience customization

Prerequisites

  • An active Loomi AI for Shopify application installed on your storefront.
  • At least one of Search, Autosuggest, or Collections active on the storefront.
  • Working knowledge of HTML and EJS templating for hands-on editing.

Navigate to the editor

  1. Open the Loomi AI for Shopify app from your Shopify admin.

  2. Click Experience customization in the app navigation.

  3. Select the template you want to edit: Search, Collections, or Autosuggest.

  4. Choose a component to expand the editor — Layout, Product card, Text facet, Slider facet, or Selected facet.

    Choose a component to expand the editor.
  5. Edit the HTML and EJS, then save. Use Revert to Bloomreach template to clear any custom configuration.

Page layout anchors

Every widget renders inside a layout root that depends on four anchor elements. Define each anchor as a single element using the exact class name shown. You can add other classes to the same element (for example, class="br-facets-container custom-sidebar-style").

⚠️

Mandatory anchors

The four class names below must exist in your markup. If an anchor is missing, Loomi AI generates an empty div with the corresponding class and attaches it to the layout root in this sequence: facets, sorting, grid, pagination.

ClassHostsUI role
br-facets-containerFacet toolbar when includeFacets is true. Loomi AI adds br-toolbar and renders facet groups, the mobile filters drawer, and related controls.Filter sidebar or top toolbar.
br-sortingThe br-sorting web component when sort options are configured. If there are no facets but sorting is enabled, br-toolbar attaches here instead. For more information, see Sorting referenceSort by control.
br-products-gridThe product grid. Loomi AI appends a child div.br-products__grid containing br-product-card elements.Product listing.
br-paginationThe br-pagination web component when pagination is enabled and totalPages > 1.Page controls.

Example

<div>
  <aside class="br-facets-container"></aside>
  <div>
    <header>
      <div class="br-sorting"></div>
    </header>
    <div class="br-products-grid"></div>
    <footer>
      <div class="br-pagination"></div>
    </footer>
  </div>
</div>

Sorting reference

The sorting component renders a dropdown that lets shoppers reorder results by criteria such as relevance, price, or newness. Use the data attributes and EJS variables on this page to customize the trigger button, option list, and selected state display.

Sorting component.

Data attributes

AttributeElementValueBehavior
data-br-actionTrigger buttonsorting-triggerClick toggles the sort dropdown open and closed.
data-br-actionEach sorting optionsorting-optionClick selects the sort option, closes the dropdown, updates the displayed label, and fires br-sort-change. The parent widget reloads results in the new sort order — the product grid and pagination update.
data-valueEach optionencodeURIComponent(option.value)Tells the component which sort key was chosen so the correct option becomes selected and the parent receives the right value in br-sort-change. Wrong or missing values prevent selection.

EJS variables

The sorting object exposes these fields:

FieldDescriptionData type
optionsAll sort options.{ label, value }[]
selectedValueCurrently selected value from the parent.string
selectedLabelLabel of the effective selection.string
effectiveSelectedValueResolved value. Falls back to the first option if selectedValue is invalid.string
labelDesktop or static label. Default "Sort by".string
mobileLabelShort label for mobile. Default "Sort".string
displayLabelmobileLabel when viewport width is <= 768px, otherwise label.string
isOpenWhether the dropdown is open.boolean
isMobiletrue when matchMedia('(max-width: 768px)') matches.boolean

Example

<button type="button" data-br-action="sorting-trigger">
  <%= sorting.displayLabel %>: <%= sorting.selectedLabel %>
</button>
<ul>
  <% sorting.options.forEach(function(option) { %>
    <li
      data-br-action="sorting-option"
      data-value="<%= encodeURIComponent(option.value) %>"
      aria-selected="<%= option.value === sorting.effectiveSelectedValue %>"
    ><%= option.label %></li>
  <% }); %>
</ul>

Pagination reference

The pagination component renders page navigation controls below the product grid, including previous and next buttons, numbered page links, and ellipsis gaps. Use the data attributes and EJS variables on this page to customize the markup and disabled states. For page layout requirements, see HTML and EJS reference for Loomi AI for Shopify.

Pagination component showing page number buttons, previous and next controls, and ellipsis gaps.

Data attributes

AttributeElementValueBehavior
data-br-actionPrevious buttonpagination-prevClick goes to the previous page when not on page 1. Fires br-page-change. The parent loads the prior result set, updates the active page styling, and refreshes the product grid.
data-br-actionNext buttonpagination-nextClick goes to the next page when not on the last page. Same refresh as prev.
data-br-actionPage number buttonpagination-pageClick jumps to that page number. Fires br-page-change and reloads results for the page.
data-br-pagePage number buttonPage number (for example, 1)Supplies the target page index for pagination-page clicks. Wrong values navigate to the wrong page or no-op.

EJS variables

The pagination object exposes these fields:

FieldDescriptionData type
currentPageActive page.number
totalPagesTotal page count.number
pageNumbersSequence to render. Uses "ellipsis" for gaps.(number | "ellipsis")[]
isPrevDisabledtrue on the first page.boolean
isNextDisabledtrue on the last page.boolean
actionsData attribute constants for event delegation: { prev: “pagination-prev”, next: “pagination-next”, page: “pagination-page” }object

Example

<button data-br-action="<%= pagination.actions.prev %>" <%= pagination.isPrevDisabled ? 'disabled' : '' %>>Prev</button>
<% pagination.pageNumbers.forEach(function(page) { %>
  <% if (page === 'ellipsis') { %>
    <span>…</span>
  <% } else { %>
    <button
      data-br-action="<%= pagination.actions.page %>"
      data-br-page="<%= page %>"
    ><%= page %></button>
  <% } %>
<% }); %>
<button data-br-action="<%= pagination.actions.next %>" <%= pagination.isNextDisabled ? 'disabled' : '' %>>Next</button>

Related articles


© Bloomreach, Inc. All rights reserved.