Skip to content

Facets container

The Facets container lists and manages search filters (facets) to refine product search results.

Import

import Facets from '@dropins/storefront-product-discovery/containers/Facets.js';

Configurations

The Facets container provides the following configuration options:

Option Type Req? Description
scopestringNo Scope identifier for isolated instances. Default: undefined.
onFilterChangefunctionNo Callback when filters are changed. Receives updated filters array.
slotsobjectNo Allows passing custom components for Facet, SelectedFacets, and Facets slots.

Basic Usage

// Basic facets container
await provider.render(Facets)($container);
// With scope and callback
await provider.render(Facets, {
scope: 'popover',
onFilterChange: (filters) => {
console.log('Filters changed:', filters);
}
})($container);

Slots

The Facets container supports several customization slots. For detailed information about available slots and their usage, see Product Discovery Slots.

Example Slot Usage

slots: {
FacetBucketLabel: (ctx) => {
// Here we are overriding the default Facet labels.
const $label = document.createElement('span');
$label.innerText = `${ctx.data.name ?? ctx.data.title} (${ctx.data.count})`;
// If the facet has an icon, add it to the label
if (ctx.data.icon) {
const $icon = document.createElement('img');
$icon.className = 'facet-bucket-label__icon';
$icon.src = ctx.data.icon;
$label.prepend($icon);
}
ctx.replaceWith($label);
},
}

Real-time Updates

The container automatically updates when search events are received:

  1. Search Results: Updates available facets based on results
  2. Filter Changes: Automatically triggers new searches with updated filters

Scope Support

The Facets container supports isolated instances through scope configuration:

// Global scope (default) Listens to all search events
await provider.render(Facets)($container);
// Only listens to events with scope: 'popover'
await provider.render(Facets, { scope: 'popover' })($container);

Selected Filters Display

  • Shows all currently selected filters as removable buttons
  • Displays filter labels with appropriate formatting (including currency for price ranges)
  • Provides individual remove functionality for each selected filter

Clear All Functionality

  • “Clear All” button to remove all selected filters at once
  • Automatically triggers a new search with no filters applied

Integration Examples

Basic PLP Setup

await provider.render(Facets)($facetsContainer);

Category-Based Filtering

await provider.render(Facets, {
onFilterChange: (filters) => {
console.log('Electronics filters changed:', filters);
}
})($electronicsFacets);

Scoped Facets

await provider.render(Facets, {
scope: 'popover',
onFilterChange: (filters) => {
// Quick search filters
console.log('Popover filters:', filters);
}
})($popoverFacets);

Best Practices

  1. Scope Management: Use unique scope identifiers for multiple instances
  2. Scope Configuration: Use appropriate scope identifiers for multiple instances
  3. Filter Callbacks: Use onFilterChange for custom filter handling
  4. Real-time Updates: Let the container handle updates automatically
  5. Performance: Use scoping to limit unnecessary updates
  6. Slot Customization: Use slots for merchant-specific facet styling

Troubleshooting

Common Issues

  1. Container Not Updating: Check scope configuration and event handling
  2. Slots Not Rendering: Ensure the element is added to the slot using ctx.appendChild(), ctx.replaceWith(), etc.
  3. Performance Issues: Use proper scoping to limit unnecessary updates
  4. Styling Conflicts: Use specific CSS classes to avoid conflicts

Facet Selection Behavior

  • Dynamic Facets: Facets are automatically generated based on search results and available product attributes.
  • Category-Relative Filtering: If a categoryPath is provided in the search, facet selections will automatically include the categoryPath to ensure filters are relative to the current category.