The SDK provides custom elements (web components) for declarative data fetching. These components automatically wait for SDK initialization, manage loading states, and provide reactive data access.
Available Providers
| Component | Description |
|---|
<commerce-blocks-browse-provider> | Browse and filter products within a collection |
<commerce-blocks-search-provider> | Semantic search across your catalog |
<commerce-blocks-similar-provider> | Find similar products |
<commerce-blocks-predictive-provider> | Autocomplete and search suggestions |
<commerce-blocks-image-search-provider> | Search by image |
App-Ready Pattern
Providers automatically wait for initialize() to complete before fetching data. This prevents race conditions when web components are added to the DOM before the SDK is initialized.
<!-- Providers can exist in HTML before initialize() -->
<commerce-blocks-browse-provider
data-collection="shoes"
data-sort="best_selling"
></commerce-blocks-browse-provider>
<script type="module">
import { initialize } from '@protonagency/commerce-blocks-sdk';
// Called after DOM is ready - providers will wait for this
initialize({
layers: {
accessToken: 'token',
store: { name: 'Store', shopDomain: 'store.myshopify.com' },
shopOptions: { metafieldNamespaces: [], attributes: [...], swatches: [...] },
},
storefront: { shop: 'store.myshopify.com' },
});
</script>
Browse Provider
Browse products within a merchandised collection with filtering, sorting, and pagination.
<commerce-blocks-browse-provider
data-collection="summer-shoes"
data-sort="best_selling"
data-page="1"
data-limit="24"
data-filters='{"conditional":"AND","expressions":[{"property":"vendor","operator":"eq","values":["Nike"]}]}'
data-facets='["vendor","color","size"]'
data-retrieve-facet-count
></commerce-blocks-browse-provider>
Attributes
The collection handle to browse.
The sort order code to apply.
The page number for pagination.
Number of products per page.
JSON string of filter groups. Filters must be wrapped in AND/OR groups.
JSON array of facet attribute codes to retrieve.
data-retrieve-facet-count
Include facet counts in the response.
Search Provider
Perform semantic search across your catalog.
<commerce-blocks-search-provider
data-query="blue running shoes"
data-page="1"
data-limit="24"
></commerce-blocks-search-provider>
Attributes
The page number for pagination.
Number of products per page.
Similar Products Provider
Find products similar to a reference product.
<commerce-blocks-similar-provider
data-product-id="1234567890"
data-limit="8"
></commerce-blocks-similar-provider>
Attributes
The product ID to find similar products for.
Number of similar products to return.
Predictive Search Provider
Get autocomplete suggestions as users type.
<commerce-blocks-predictive-provider
data-query="sho"
data-limit="5"
></commerce-blocks-predictive-provider>
Attributes
The partial search query for suggestions.
Number of suggestions to return.
Image Search Provider
Search for products using an uploaded image.
<commerce-blocks-image-search-provider
data-limit="24"
></commerce-blocks-image-search-provider>
Attributes
Number of products to return.
Accessing Provider State
Providers expose state via properties that you can access programmatically:
const provider = document.querySelector('commerce-blocks-browse-provider');
// Access current state
console.log(provider.data); // The response data
console.log(provider.isFetching); // Currently fetching
console.log(provider.isLoading); // Initial load in progress
console.log(provider.isStale); // Data from cache, may need refresh
console.log(provider.error); // Any error that occurred
Custom Card Rendering
Providers support custom card templates using Preact and HTM:
const provider = document.querySelector('commerce-blocks-browse-provider');
// Set a custom card template
provider.setCustomCard(`
({ data, isLoading, error }) => {
if (isLoading) return html\`<div>Loading...</div>\`;
if (error) return html\`<div>Error: \${error.message}</div>\`;
return html\`
<div class="product-grid">
\${data.results.map(product => html\`
<div class="product-card">
<img src="\${product.image?.src}" alt="\${product.title}" />
<h3>\${product.title}</h3>
<p>\${product.price}</p>
</div>
\`)}
</div>
\`;
}
`);
The html tagged template is available inside card templates for creating Preact elements.
Update provider input programmatically to change filters, pagination, or other parameters:
import { filter } from '@protonagency/commerce-blocks-sdk/utils';
const provider = document.querySelector('commerce-blocks-browse-provider');
// Update input (use filter builder for cleaner syntax)
provider.setInput({
pagination: { page: 2 },
filterGroup: filter.eq('vendor', 'Nike'), // Returns wrapped AND group
});
// Force refresh
provider.refresh();
Extending Providers
For custom widgets, extend the base provider classes and access the reactive signal:
import { render } from 'preact';
import { BrowseProvider } from '@protonagency/commerce-blocks-sdk/components';
import type { ReadonlySignal } from '@preact/signals';
import type { DataState, BrowseResponse } from '@protonagency/commerce-blocks-sdk';
class MyBrowseWidget extends BrowseProvider {
private container: HTMLDivElement | null = null;
connectedCallback() {
super.connectedCallback(); // Required - sets up the signal
this.container = document.createElement('div');
this.appendChild(this.container);
// Access the reactive signal via this.signal
render(<MyComponent signal={this.signal} />, this.container);
}
disconnectedCallback() {
if (this.container) {
render(null, this.container);
}
super.disconnectedCallback();
}
}
// Your Preact component receives the signal
function MyComponent({ signal }: { signal: ReadonlySignal<DataState<BrowseResponse>> }) {
const { data, error, status } = signal.value;
// ... render based on state
}
// Register the custom element
customElements.define('my-browse-widget', MyBrowseWidget);
Available Base Providers
| Provider | Signal Type |
|---|
BrowseProvider | DataState<BrowseResponse> |
SearchProvider | DataState<SearchResponse> |
SimilarProvider | DataState<SimilarProductsResponse> |
PredictiveProvider | DataState<PredictiveSearchResponse> |
ImageSearchProvider | DataState<ImageSearchResponse> |