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
import SearchResults from '@dropins/storefront-product-discovery/containers/SearchResults.js';
Configurations
The SearchResults
container provides the following configuration options:
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);
Slots
The SearchResults
container supports several customization slots. For detailed information about available slots and their usage, see Product Discovery Slots.
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
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
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
Customize how products link to their detail pages:
// Basic product routingrouteProduct: (product) => `/product/${product.sku}`
Integration Examples
Basic PLP Setup
await provider.render(SearchResults, { skeletonCount: 12, routeProduct: (product) => `/product/${product.sku}`})($searchResults);
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
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
- 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
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