Overview

Use the data attribute with a Mustache-style template ({{window.PRODUCT_RESPONSE_X.products}}) inside an <mmm-data-source> wrapper. Each item is exposed to children as {{item}} (or rename via item-alias). Layout is grid-by-default with per-breakpoint columns; switch to flex with ui-type="flex".

Quick start

<script src="https://v2-api-production.commmerce.com/api/v1/web-component/commmerce-sdk.js?store=sample-store"></script>

<mmm-data-source api="product.getProductList" response-key="grid">
  <mmm-loop data="{{window.PRODUCT_RESPONSE_GRID.products}}" xl-columns="4" desktop-columns="4" tablet-columns="2" mobile-columns="2" gap="1rem">
    <mmm-product-card data-product="{{item}}"></mmm-product-card>
  </mmm-loop>
</mmm-data-source>

Core attributes

AttributeTypeDefaultDescription
datastring / templateData source. Either a JSON-array string or a {{path}} template pointing at a global / SSR variable.
ui-typestringflexflex, inline-flex, grid, inline-grid, block, inline, or inline-block.
directionstringrowrow, column, row-reverse, column-reverse (aliases horizontal / vertical accepted).
wrapstringwrapwrap, nowrap, or wrap-reverse.
columnsnumberNumber of columns (grid).
gapstring0.625remCSS gap between items.
countnumberallCap the number of items rendered.
item-aliasstringPrefix used in template placeholders; e.g. item-alias="product" makes {{product.title}} resolve to item.title.
background-colorstringwhiteLoop wrapper background.
paddingstring0 0.375remLoop wrapper padding.
debugbooleanfalsePrint render logs to console for debugging.

Responsive columns & counts

Per-breakpoint overrides. Both hyphenated and lowercase-merged forms work.

AttributeTypeDefaultDescription
xl-columns / xlcolumnsnumbercolumnsColumns above ~1280px.
desktop-columns / desktopcolumnsnumbercolumnsColumns 768–1280px.
tablet-columns / tabletcolumnsnumbercolumnsColumns 430–768px.
mobile-columns / mobilecolumnsnumbercolumnsColumns below 430px.
xl-count / xlcountnumbercountItem count cap on XL viewports.
desktop-count / desktopcountnumbercountDesktop item cap.
tablet-count / tabletcountnumbercountTablet item cap.
mobile-count / mobilecountnumbercountMobile item cap.

Events

EventTargetPayload
loop-renderedelement (bubbles){ itemCount: number, id: string, hasRealData: boolean }

Live preview

store sample-store tag <mmm-loop>

Examples

1. Product grid

<mmm-data-source api="product.getProductList" response-key="grid">
  <mmm-loop data="{{window.PRODUCT_RESPONSE_GRID.products}}" xl-columns="4" mobile-columns="2" gap="1rem">
    <mmm-product-card data-product="{{item}}"></mmm-product-card>
  </mmm-loop>
</mmm-data-source>

2. Capped count for "Latest 8"

<mmm-loop data="{{window.PRODUCT_RESPONSE_GRID.products}}" columns="4" count="8" gap="1rem">
  <mmm-product-card data-product="{{item}}"></mmm-product-card>
</mmm-loop>

3. Nested loop with aliasing

<mmm-loop data="{{window.CATEGORIES}}" item-alias="cat">
  <section>
    <h2>{{cat.name}}</h2>
    <mmm-loop data="{{cat.products}}">
      <mmm-product-card data-product="{{item}}"></mmm-product-card>
    </mmm-loop>
  </section>
</mmm-loop>

4. React to render completion

document.querySelector('mmm-loop').addEventListener('loop-rendered', (e) => {
  console.log('Rendered', e.detail.count, 'items');
});