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 currentProduct, recId, and routing through routeProduct callbacks.

Configurations
Section titled “Configurations”The ProductList container provides the following configuration options:
Product context
Section titled “Product context”Pass product context with the optional currentProduct prop:
currentProduct?: { sku: string; price?: number };How context is supplied depends on where the unit is rendered:
- PDP pages: The Commerce boilerplate block reads
currentProductfrom the Adobe Client Data Layer (ACDL) product context. You do not need to passcurrentProductin block configuration. - Non-PDP pages: Set
currentskuand/orcurrentpricein the product-recommendations block configuration table to provide product context explicitly. - Context-free units: If neither
currentskunor ACDL product context is available,currentProductisundefined. The dropin still renders as long asrecIdis provided.
Query routing
Section titled “Query routing”The container selects a GraphQL query based on the currentProduct shape:
- When
currentProduct.priceis present (Adobe Commerce Optimizer and Adobe Commerce as a Cloud Service only), the container usesGetRecommendationsByUnitIdsWithCurrentProduct, which supports dynamic price filter operators. - When only
currentProduct.skuis present, orcurrentProductis absent, the container usesGetRecommendationsByUnitIds, which is compatible with all backend types, including PaaS.
The ProductListProps interface has the following shape:
export interface ProductListProps extends HTMLAttributes<HTMLDivElement> { recId: string; currentProduct?: { sku: string; price?: number; }; /** @deprecated As of v4.0.3. Use `currentProduct` instead. */ 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; inStock?: boolean;}
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
Section titled “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
Section titled “Example configuration”The following example demonstrates how to render the ProductList container with recId, currentProduct, and routeProduct callbacks with different slots:
// Render Containerprovider.render(ProductList, { recId: 'recommendation-unit-1', routeProduct: (item) => `/products/${item.urlKey}`, currentProduct: { sku: 'ADB150', price: 49.99 }, 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.item.itemType === 'SimpleProductView') { // Add to Cart Button UI.render(Button, { children: 'Add to Cart', onClick: ctx.item.inStock ? () => { // Call add to cart function from cart/api console.log('Add to Cart'); } : undefined, variant: 'primary', disabled: !ctx.item.inStock, })(addToCart); } else { // View Product Button UI.render(Button, { children: 'Select Options', onClick: () => { console.log('Select Options'); window.location.href = ctx.item.urlKey; }, variant: 'tertiary', })(addToCart); } ctx.replaceWith(wrapper); }, },}));Key Features
Section titled “Key Features”- Automatic Data Fetching: Fetches recommendations based on
currentProduct(or legacycurrentSku) 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