
{% doc %}
@prompt
Create a dynamic SKU display that automatically updates when product variants are changed without requiring a page refresh. The SKU should be visible on the product page and change instantly when customers select different variant options like size, color, or other attributes.
{% enddoc %}
{% assign ai_gen_id = block.id | replace: '_', '' | downcase %}
{% style %}
.ai-sku-display-{{ ai_gen_id }} {
display: flex;
align-items: center;
gap: 8px;
padding: {{ block.settings.padding }}px;
background-color: {{ block.settings.background_color }};
border: {{ block.settings.border_width }}px solid {{ block.settings.border_color }};
border-radius: {{ block.settings.border_radius }}px;
font-family: {{ block.settings.font_family }};
font-size: {{ block.settings.font_size }}px;
color: {{ block.settings.text_color }};
margin: {{ block.settings.margin_top }}px 0 {{ block.settings.margin_bottom }}px 0;
}
.ai-sku-display__label-{{ ai_gen_id }} {
font-weight: {{ block.settings.label_font_weight }};
color: {{ block.settings.label_color }};
{% if block.settings.label_uppercase %}
text-transform: uppercase;
{% endif %}
}
.ai-sku-display__value-{{ ai_gen_id }} {
font-weight: {{ block.settings.value_font_weight }};
color: {{ block.settings.value_color }};
font-family: monospace;
{% if block.settings.value_uppercase %}
text-transform: uppercase;
{% endif %}
}
.ai-sku-display__unavailable-{{ ai_gen_id }} {
color: {{ block.settings.unavailable_color }};
font-style: italic;
}
@media screen and (max-width: 749px) {
.ai-sku-display-{{ ai_gen_id }} {
font-size: {{ block.settings.font_size | times: 0.9 }}px;
padding: {{ block.settings.padding | times: 0.8 }}px;
}
}
{% endstyle %}
<dynamic-sku-display-{{ ai_gen_id }}
class="ai-sku-display-{{ ai_gen_id }}"
data-product-id="{{ product.id }}"
{{ block.shopify_attributes }}
>
<span class="ai-sku-display__label-{{ ai_gen_id }}">
{{ block.settings.label_text }}
</span>
<span
class="ai-sku-display__value-{{ ai_gen_id }}"
data-sku-value
>
{% if product.selected_or_first_available_variant.sku != blank %}
{{ product.selected_or_first_available_variant.sku }}
{% else %}
<span class="ai-sku-display__unavailable-{{ ai_gen_id }}">
{{ block.settings.no_sku_text }}
</span>
{% endif %}
</span>
</dynamic-sku-display-{{ ai_gen_id }}>
<script>
(function() {
class DynamicSkuDisplay{{ ai_gen_id }} extends HTMLElement {
constructor() {
super();
this.productId = this.dataset.productId;
this.skuValueElement = this.querySelector('[data-sku-value]');
this.noSkuText = '{{ block.settings.no_sku_text | escape }}';
this.unavailableClass = 'ai-sku-display__unavailable-{{ ai_gen_id }}';
}
connectedCallback() {
this.setupVariantChangeListener();
this.setupUrlChangeListener();
}
setupVariantChangeListener() {
document.addEventListener('variant:change', (event) => {
if (event.detail && event.detail.variant) {
this.updateSku(event.detail.variant);
}
});
const variantSelectors = document.querySelectorAll('variant-radios, variant-selects');
variantSelectors.forEach(selector => {
selector.addEventListener('change', (event) => {
const selectedVariant = this.getSelectedVariant();
if (selectedVariant) {
this.updateSku(selectedVariant);
}
});
});
const variantInputs = document.querySelectorAll('input[name="id"], select[name="id"]');
variantInputs.forEach(input => {
input.addEventListener('change', () => {
const selectedVariant = this.getSelectedVariant();
if (selectedVariant) {
this.updateSku(selectedVariant);
}
});
});
}
setupUrlChangeListener() {
const observer = new MutationObserver(() => {
const urlParams = new URLSearchParams(window.location.search);
const variantId = urlParams.get('variant');
if (variantId) {
this.fetchVariantData(variantId);
}
});
observer.observe(document, { subtree: true, childList: true });
window.addEventListener('popstate', () => {
const urlParams = new URLSearchParams(window.location.search);
const variantId = urlParams.get('variant');
if (variantId) {
this.fetchVariantData(variantId);
}
});
}
getSelectedVariant() {
const variantInput = document.querySelector('input[name="id"]:checked, select[name="id"]');
if (!variantInput) return null;
const variantId = variantInput.value;
return this.getVariantById(variantId);
}
getVariantById(variantId) {
if (!window.productVariants) {
this.fetchProductData();
return null;
}
return window.productVariants.find(variant => variant.id == variantId);
}
async fetchProductData() {
try {
const response = await fetch(`/products/${window.location.pathname.split('/').pop()}.js`);
const product = await response.json();
window.productVariants = product.variants;
} catch (error) {
console.error('Error fetching product data:', error);
}
}
async fetchVariantData(variantId) {
try {
const response = await fetch(`/products/${window.location.pathname.split('/').pop()}.js`);
const product = await response.json();
const variant = product.variants.find(v => v.id == variantId);
if (variant) {
this.updateSku(variant);
}
} catch (error) {
console.error('Error fetching variant data:', error);
}
}
updateSku(variant) {
if (!this.skuValueElement) return;
this.skuValueElement.classList.remove(this.unavailableClass);
if (variant.sku && variant.sku.trim() !== '') {
this.skuValueElement.textContent = variant.sku;
} else {
this.skuValueElement.innerHTML = `<span class="${this.unavailableClass}">${this.noSkuText}</span>`;
}
this.dispatchEvent(new CustomEvent('sku:updated', {
detail: {
sku: variant.sku,
variant: variant
},
bubbles: true
}));
}
}
customElements.define('dynamic-sku-display-{{ ai_gen_id }}', DynamicSkuDisplay{{ ai_gen_id }});
})();
</script>
{% schema %}
{
"name": "Dynamic SKU Display",
"settings": [
{
"type": "header",
"content": "Content"
},
{
"type": "text",
"id": "label_text",
"label": "Label text",
"default": "SKU:"
},
{
"type": "text",
"id": "no_sku_text",
"label": "No SKU text",
"default": "N/A"
},
{
"type": "header",
"content": "Styling"
},
{
"type": "select",
"id": "font_family",
"label": "Font family",
"options": [
{
"value": "inherit",
"label": "Inherit"
},
{
"value": "Arial, sans-serif",
"label": "Arial"
},
{
"value": "Georgia, serif",
"label": "Georgia"
},
{
"value": "monospace",
"label": "Monospace"
}
],
"default": "inherit"
},
{
"type": "range",
"id": "font_size",
"min": 10,
"max": 24,
"step": 1,
"unit": "px",
"label": "Font size",
"default": 14
},
{
"type": "color",
"id": "text_color",
"label": "Text color",
"default": "#000000"
},
{
"type": "color",
"id": "background_color",
"label": "Background color",
"default": "#f8f8f8"
},
{
"type": "header",
"content": "Label Style"
},
{
"type": "color",
"id": "label_color",
"label": "Label color",
"default": "#666666"
},
{
"type": "select",
"id": "label_font_weight",
"label": "Label font weight",
"options": [
{
"value": "normal",
"label": "Normal"
},
{
"value": "bold",
"label": "Bold"
},
{
"value": "600",
"label": "Semi-bold"
}
],
"default": "normal"
},
{
"type": "checkbox",
"id": "label_uppercase",
"label": "Uppercase label",
"default": false
},
{
"type": "header",
"content": "SKU Value Style"
},
{
"type": "color",
"id": "value_color",
"label": "SKU value color",
"default": "#000000"
},
{
"type": "select",
"id": "value_font_weight",
"label": "SKU value font weight",
"options": [
{
"value": "normal",
"label": "Normal"
},
{
"value": "bold",
"label": "Bold"
},
{
"value": "600",
"label": "Semi-bold"
}
],
"default": "bold"
},
{
"type": "checkbox",
"id": "value_uppercase",
"label": "Uppercase SKU value",
"default": false
},
{
"type": "color",
"id": "unavailable_color",
"label": "Unavailable SKU color",
"default": "#999999"
},
{
"type": "header",
"content": "Border & Spacing"
},
{
"type": "range",
"id": "padding",
"min": 0,
"max": 30,
"step": 2,
"unit": "px",
"label": "Padding",
"default": 12
},
{
"type": "range",
"id": "margin_top",
"min": 0,
"max": 50,
"step": 2,
"unit": "px",
"label": "Top margin",
"default": 10
},
{
"type": "range",
"id": "margin_bottom",
"min": 0,
"max": 50,
"step": 2,
"unit": "px",
"label": "Bottom margin",
"default": 10
},
{
"type": "range",
"id": "border_width",
"min": 0,
"max": 4,
"step": 1,
"unit": "px",
"label": "Border width",
"default": 1
},
{
"type": "color",
"id": "border_color",
"label": "Border color",
"default": "#e0e0e0"
},
{
"type": "range",
"id": "border_radius",
"min": 0,
"max": 20,
"step": 1,
"unit": "px",
"label": "Border radius",
"default": 4
}
],
"presets": [
{
"name": "Dynamic SKU Display"
}
]
}
{% endschema %}