Skip to main content
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

ComponentDescription
<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

data-collection
string
required
The collection handle to browse.
data-sort
string
required
The sort order code to apply.
data-page
number
default:"1"
The page number for pagination.
data-limit
number
default:"24"
Number of products per page.
data-filters
string
JSON string of filter groups. Filters must be wrapped in AND/OR groups.
data-facets
string
JSON array of facet attribute codes to retrieve.
data-retrieve-facet-count
boolean
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

data-query
string
required
The search query string.
data-page
number
default:"1"
The page number for pagination.
data-limit
number
default:"24"
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

data-product-id
string
required
The product ID to find similar products for.
data-limit
number
default:"8"
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

data-query
string
required
The partial search query for suggestions.
data-limit
number
default:"5"
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

data-limit
number
default:"24"
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.

Updating Provider Input

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

ProviderSignal Type
BrowseProviderDataState<BrowseResponse>
SearchProviderDataState<SearchResponse>
SimilarProviderDataState<SimilarProductsResponse>
PredictiveProviderDataState<PredictiveSearchResponse>
ImageSearchProviderDataState<ImageSearchResponse>