Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

ProductList container

The ProductList container manages and displays a list of recommended products based on the current product. Its behavior is driven by configuration options such as currentSku, recId, and routing through routeProduct callbacks.

ProductList container

ProductList container

Configurations

The ProductList container provides the following configuration options:

OptionTypeReq?Description
recIdstringYesUnique identifier for the recommendation unit.
currentSkustringYesCurrent SKU for recommendation context.
cartSkusstring[]NoCart SKUs for recommendation context.
userPurchaseHistoryany[]NoUser Purchase History for recommendation context.
userViewHistoryany[]NoUser View History for recommendation context.
routeProductfunctionNoCallback function that returns a product URL.
hideHeadingbooleanNoHide recommendations heading text.
initialDataobjectNoPre-loaded recommendation data to avoid initial fetch.
slotsobjectNoSlots for customizing heading, thumbnail, price, title, SKU, and footer.

The ProductListProps interface has the following shape:

export interface ProductListProps extends HTMLAttributes<HTMLDivElement> {
recId: string;
currentSku: string;
initialData?: {
recommendations?: {
results: RecommendationUnitModel[];
totalProducts: number;
};
};
hideHeading?: boolean;
routeProduct?: (item: Item) => string;
cartSkus?: string[];
userPurchaseHistory?: any[];
userViewHistory?: any[];
slots?: {
Heading?: SlotProps;
Footer?: SlotProps;
Title?: SlotProps<{
item: Item;
productUrl: string;
}>;
Sku?: SlotProps<{
item: Item;
}>;
Price?: SlotProps<{
item: Item;
}>;
Thumbnail?: SlotProps<{
item: any;
defaultImageProps: ImageProps;
}>;
};
}

The RecommendationUnitModel object has the following shape:

export interface RecommendationUnitModel {
displayOrder: number;
pageType: PageType;
title: string;
items: Item[];
totalProducts: number;
typeId: string;
unitId: string;
unitName: string;
}
export type PageType = 'Product'; // Always hardcoded to 'Product' per requirements
export interface Item {
uid: string;
sku: string;
name: string;
urlKey: string;
images: ItemImage[];
price: FinalPrice;
priceRange?: {
minimum?: FinalPrice;
maximum?: FinalPrice;
};
visibility: string;
queryType: string;
itemType: string;
}
interface ItemImage {
label: string;
roles: string[];
url: string;
}
export interface Price {
value: number | null;
currency: string | null;
}
export interface FinalPrice {
final?: {
amount?: Price;
};
}
export interface RecommendationsResponse {
results: RecommendationUnitModel[];
totalResults: number;
}
export interface GraphQLResponse {
errors?: Array<{ message: string }>;
data?: {
recommendations: RecommendationsResponse;
};
}

Supported Slots

The ProductList container supports the following slots:

  • Heading - Customize the recommendations heading
  • Footer - Customize the action button area (Add to Cart / View Product)
  • Title - Customize the product title display
  • Sku - Customize the SKU display
  • Price - Customize the price display
  • Thumbnail - Customize the product image display

Each slot receives context data relevant to its purpose, allowing for highly customizable product displays.

Example configuration

The following example demonstrates how to render the ProductList container with the recId, currentSku, and routeProduct callbacks with different slots:

// Render Container
provider.render(ProductList, {
recId: 'recommendation-unit-1',
routeProduct: (item) => `/products/${item.urlKey}`,
currentSku: 'ADB150',
hideHeading: false,
slots: {
// Example of how to prepend or append to the default Heading
Heading: (ctx) => {
const heading = document.createElement('div');
heading.innerText = 'Slot: Content before default heading';
ctx.prependChild(heading);
const footer = document.createElement('div');
footer.innerText = 'Slot: Content after default heading';
ctx.appendChild(footer);
},
// Example of how to prepend or append to the default Thumbnail
Thumbnail: (ctx) => {
const thumbnail = document.createElement('div');
thumbnail.innerText = 'Slot: Content before default thumbnail';
ctx.prependChild(thumbnail);
const footer = document.createElement('div');
footer.innerText = 'Slot: Content after default thumbnail';
ctx.appendChild(footer);
},
// Example of how to prepend or append to the default Price
Price: (ctx) => {
const price = document.createElement('div');
price.innerText = 'Slot: Content before default price';
ctx.prependChild(price);
const footer = document.createElement('div');
footer.innerText = 'Slot: Content after default price';
ctx.appendChild(footer);
},
// Example of how to replace default Footer with a custom footer based on product type
Footer: (ctx) => {
const wrapper = document.createElement('div');
wrapper.className = 'footer__wrapper';
const addToCart = document.createElement('div');
addToCart.className = 'footer__button--add-to-cart';
wrapper.appendChild(addToCart);
if (ctx.product.itemType === 'SimpleProductView') {
// Add to Cart Button
UI.render(Button, {
children: 'Add to Cart',
onClick: () => {
// Call add to cart function from cart/api
console.log('Add to Cart');
},
variant: 'primary',
})(addToCart);
} else {
// View Product Button
UI.render(Button, {
children: 'Select Options',
onClick: () => {
console.log('Select Options');
window.location.href = ctx.product.urlKey;
},
variant: 'tertiary',
})(addToCart);
}
ctx.replaceWith(wrapper);
},
},
}));

Key Features

  • Automatic Data Fetching: Fetches recommendations based on currentSku and other context
  • Intersection Observer: Automatically tracks when recommendations are viewed
  • Event Publishing: Publishes render and view events for analytics
  • Loading States: Handles loading states during data fetching
  • Empty States: Gracefully handles empty recommendation results
  • Internationalization: Supports multiple languages through i18n
  • Customizable Slots: Extensive customization options for all UI elements