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
Configurations
The ProductList
container provides the following configuration options:
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 Containerprovider.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