SearchResults container
The SearchResults container shows products from a search. You can customize it with slots, run separate instances, and it takes care of loading, errors, and real-time updates.
Import
Section titled “Import”import SearchResults from '@dropins/storefront-product-discovery/containers/SearchResults.js';Configurations
Section titled “Configurations”The SearchResults container provides the following configuration options:
Basic Usage
Section titled “Basic Usage”// Basic search results containerawait provider.render(SearchResults, { skeletonCount: 12, routeProduct: (product) => `/product/${product.sku}`})($container);
// With scope for isolated instanceawait provider.render(SearchResults, { skeletonCount: 6, scope: 'popover', routeProduct: (product) => `/product/${product.sku}`})($container);
// With callback for custom handlingawait provider.render(SearchResults, { skeletonCount: 12, onSearchResult: (products) => { console.log('Received', products.length, 'results'); }})($container);The SearchResults container supports several customization slots. For detailed information about available slots and their usage, see Product Discovery Slots.
Example Slot Usage
Section titled “Example Slot Usage”slots: { Header: (ctx) => { const header = document.createElement('div'); header.innerHTML = ` <h2>Search Results</h2> <p>Found ${ctx.products.length} products</p> `; ctx.appendChild(header); },
ProductActions: (ctx) => { const actions = document.createElement('div');
const addToCartBtn = document.createElement('button'); addToCartBtn.textContent = 'Add to Cart'; addToCartBtn.onclick = () => addToCart(ctx.product);
const quickViewBtn = document.createElement('button'); quickViewBtn.textContent = 'Quick View'; quickViewBtn.onclick = () => openQuickView(ctx.product);
actions.appendChild(addToCartBtn); actions.appendChild(quickViewBtn);
ctx.appendChild(actions); }}Features
Section titled “Features”Automatic Loading States
Section titled “Automatic Loading States”- Skeleton Loading: Configurable skeleton items while fetching results
- Loading Indicators: Automatic loading state management
- Error Handling: Graceful error display with user-friendly messages
- Empty States: Appropriate messaging when no results are found
Real-time Updates
Section titled “Real-time Updates”The container automatically updates when search events are received:
- Search Start: Shows loading state with skeleton items
- Search Results: Updates with new product data
- Search Complete: Removes loading state
- Error Handling: Displays error state if applicable
Product Routing
Section titled “Product Routing”Customize how products link to their detail pages:
// Basic product routingrouteProduct: (product) => `/product/${product.sku}`Integration Examples
Section titled “Integration Examples”Basic PLP Setup
Section titled “Basic PLP Setup”await provider.render(SearchResults, { skeletonCount: 12, routeProduct: (product) => `/product/${product.sku}`})($searchResults);Quick Search Popover
Section titled “Quick Search Popover”await render.render(SearchResults, { skeletonCount: pageSize, scope: 'popover', routeProduct: ({ urlKey, sku }) => rootLink(`/products/${urlKey}/${sku}`), onSearchResult: (results) => { searchResult.style.display = results.length > 0 ? 'block' : 'none'; }, 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 || '')}`, })); }); }, },})(searchResult);Search Results Integration
Section titled “Search Results Integration”await provider.render(SearchResults, { routeProduct: (product) => rootLink(`/products/${product.urlKey}/${product.sku}`), slots: { ProductActions: (ctx) => { // Wrapper const wrapper = document.createElement('div'); wrapper.className = 'product-discovery-product-actions';
// Add to Cart Button const addToCartBtn = document.createElement('button'); addToCartBtn.className = 'product-discovery-product-actions__add-to-cart'; addToCartBtn.innerText = placeholders.Global.AddToCartLabel; addToCartBtn.addEventListener('click', () => console.log(ctx.product));
// Append element to Slot ctx.appendChild(addToCartBtn); }, },})($productList);Best Practices
Section titled “Best Practices”- Scope Management: Use unique scope identifiers for multiple instances
- Slot Customization: Use slots for merchant-specific customization
- Performance: Use lazy loading for off-screen containers
- Error Handling: Let the container handle errors automatically
- Real-time Updates: Let the container handle updates automatically
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”- Container Not Updating: Check scope configuration and event handling
- Slots Not Rendering: Ensure the element is added to the slot using
ctx.appendChild(),ctx.replaceWith(), etc. - Styling Conflicts: Use specific CSS classes to avoid conflicts