Skip to content

Product Discovery Slots

The Product Discovery drop-in exposes 12 slots in 2 containers for customizing specific UI sections. Use slots to replace or extend container components. For default properties available to all slots, see Extending drop-in components.

Version: 2.1.0
ContainerSlots
FacetsFacet, SelectedFacets, Facets, FacetBucket, FacetBucketLabel
SearchResultsProductActions, ProductPrice, ProductName, ProductImage, NoResults, Header, Footer

Facets slots

interface FacetsProps
slots?: {
Facet?: SlotProps<{ data: SearchFacet }>;
SelectedFacets?: SlotProps<{ data: SearchFacet[] }>;
Facets?: SlotProps<{ data: SearchFacet[] }>;
FacetBucket?: SlotProps<{ data: FacetBucket }>;
FacetBucketLabel?: SlotProps<{ data: FacetBucket }>;
};

SearchResults slots

interface SearchResultsProps
slots?: {
ProductActions?: SlotProps<SlotDefaultContext>;
ProductPrice?: SlotProps<SlotDefaultContext>;
ProductName?: SlotProps<SlotDefaultContext>;
ProductImage?: SlotProps<SlotDefaultContext & { defaultImageProps: ImageProps }>;
NoResults?: SlotProps<{ error: string | null; variables: SearchVariables | null }>;
Header?: SlotProps<{ products: Product[]; variables: SearchVariables | null }>;
Footer?: SlotProps<{ products: Product[]; variables: SearchVariables | null }>;
};

ProductActions example

This example from the Product List Page block shows how to customize the ProductActions slot:

import { render as provider } from '@dropins/storefront-product-discovery/render.js';
import SearchResults from '@dropins/storefront-product-discovery/containers/SearchResults.js';
import { Button, Icon, provider as UI } from '@dropins/tools/components.js';
import { h } from '@dropins/tools/preact.js';
import { WishlistToggle } from '@dropins/storefront-wishlist/containers/WishlistToggle.js';
import { render as wishlistRender } from '@dropins/storefront-wishlist/render.js';
// Note: `getAddToCartButton` should be defined in your block context (helper function to create add to cart button)
provider.render(SearchResults, {
slots: {
ProductActions: (ctx) => {
const actionsWrapper = document.createElement('div');
actionsWrapper.className = 'product-discovery-product-actions';
// Add to Cart Button
const addToCartBtn = getAddToCartButton(ctx.product);
addToCartBtn.className = 'product-discovery-product-actions__add-to-cart';
// Wishlist Button
const $wishlistToggle = document.createElement('div');
$wishlistToggle.classList.add('product-discovery-product-actions__wishlist-toggle');
wishlistRender.render(WishlistToggle, {
product: ctx.product,
variant: 'tertiary',
})($wishlistToggle);
actionsWrapper.appendChild(addToCartBtn);
actionsWrapper.appendChild($wishlistToggle);
ctx.replaceWith(actionsWrapper);
}
}
})(document.querySelector('.search-results'));

ProductImage example

This example from the Product List Page block shows how to customize the ProductImage slot:

import { render as provider } from '@dropins/storefront-product-discovery/render.js';
import SearchResults from '@dropins/storefront-product-discovery/containers/SearchResults.js';
import { tryRenderAemAssetsImage } from '@dropins/tools/lib/aem/assets.js';
import { getProductLink } from '../../scripts/commerce.js';
provider.render(SearchResults, {
slots: {
ProductImage: (ctx) => {
const { product, defaultImageProps } = ctx;
const anchorWrapper = document.createElement('a');
anchorWrapper.href = getProductLink(product.urlKey, product.sku);
tryRenderAemAssetsImage(ctx, {
alias: product.sku,
imageProps: defaultImageProps,
wrapper: anchorWrapper,
params: {
width: defaultImageProps.width,
height: defaultImageProps.height,
},
});
}
}
})(document.querySelector('.search-results'));

This example from the Header block shows how to customize the Footer slot:

import { render as provider } from '@dropins/storefront-product-discovery/render.js';
import SearchResults from '@dropins/storefront-product-discovery/containers/SearchResults.js';
import { rootLink } from '../../scripts/commerce.js';
// Note: `labels` and `recommendationsData` should be defined in your block context
provider.render(SearchResults, {
slots: {
Footer: async (ctx) => {
// View all results button
const viewAllResultsWrapper = document.createElement('div');
const viewAllResultsButton = await UI.render(Button, {
children: labels.Global?.SearchViewAll,
variant: 'secondary',
href: rootLink('/search'),
})(viewAllResultsWrapper);
ctx.appendChild(viewAllResultsWrapper);
ctx.onChange((next) => {
viewAllResultsButton?.setProps((prev) => ({
...prev,
href: `${rootLink('/search')}?q=${encodeURIComponent(next.variables?.phrase || '')}`,
}));
});
}
}
})(document.querySelector('.search-results'));