ProductCard Web Component
Imagine a bustling storefront where each product card feels alive: clicking a color swatch instantly refreshes the main image. The ProductCard component brings this magic to life, transforming static HTML into an interactive showcase.
What It Does
assets/component-product-card.js exports a custom element named <product-card>. It:
- Listens for swatch clicks within each card.
- Updates the main product image based on the selected variant.
- Toggles a selected state on swatches.
All of this happens without a page reload, creating a seamless shopper experience .
API Overview
| Method | Purpose |
|---|---|
| constructor() | Initializes the HTMLElement by calling super(). |
| connectedCallback | Attaches click listeners to each .color-swatch. |
| onSwatchClick | Handles swatch interaction: updates image URL, srcset, and UI. |
Detailed Method Documentation
constructor()
The story begins here.
When a <product-card> is instantiated, its constructor calls super(), inheriting all standard element behavior.
constructor() {
super();
}No additional setup occurs here; the magic starts in connectedCallback() .
connectedCallback()
As soon as the element enters the DOM, connectedCallback awakens. It:
- Finds all elements with
.color-swatch. - Binds the
clickevent to each swatch. - Ensures
thisinside the handler refers to the card instance.
connectedCallback() {
this.querySelectorAll('.color-swatch')
.forEach(s => s.addEventListener('click', this.onSwatchClick.bind(this)));
}This sets the stage for responsive swatch interactions .
onSwatchClick(event)
When a shopper clicks a swatch, onSwatchClick takes the lead:
- Identify the clicked swatch (
event.target). - Locate the main image using a matching
data-product-imageattribute. - Extract the variant’s image URL and
srcset: - First from a nested
.data-variant-imageelement. - Otherwise directly from the swatch element.
- Deselect all swatches, then select the clicked one.
- Update the main
<img>’ssrcandsrcsetif available.
onSwatchClick(event) {
const swatch = event.target;
const productImage = this.querySelector(
`[data-product-image="${this.dataset.productId}"]`
);
// Get new URLs
const swatchImage = swatch.querySelector('.data-variant-image');
let newImageUrl = swatchImage?.getAttribute('src') || swatch.getAttribute('src');
let newSrcset = swatchImage?.getAttribute('srcset') || swatch.getAttribute('srcset');
// Update swatch UI
this.querySelectorAll('.color-swatch').forEach(s => s.classList.remove('selected'));
swatch.classList.add('selected');
// Swap the main image
if (productImage && newImageUrl) {
productImage.src = newImageUrl;
productImage.srcset = newSrcset;
}
}This elegant flow swaps product visuals in an instant .
Custom Element Definition
To avoid redefinitions, the script checks if <product-card> is already registered:
if (!customElements.get('product-card')) {
customElements.define('product-card', ProductCard);
}This ensures compatibility with other scripts and hot-reloading scenarios .
Integration with Shopify Liquid
On the server, a Liquid snippet injects the <product-card> wrapper:
<product-card class="product-card" data-product-id="{{ card_product.id }}">
<!-- Card markup with .color-swatch spans and data-variant-image -->
</product-card>This snippet lives in snippets/component-product-card.liquid, linking the JavaScript and HTML glue .
Usage Example
- Render a product card in Liquid:
{% render 'component-product-card',
card_product: product,
enable_swatches: true,
swatch_trigger: 'Color' %}Ensure your HTML includes:
data-product-idon<product-card>Main
<img>withdata-product-image="\{\{ product.id \}\}".color-swatchelements with optional nested.data-variant-imageInclude the module:
<script src="\{\{ 'component-product-card.js' | asset_url \}\}" type="module"></script>With these pieces in place, shoppers can click swatches and see instant image updates—no page reload needed! 🎨