How to Create Dynamic Product Cards with Swatches in Shopify

How to Create Dynamic Product Cards with Swatches in Shopify

Learn how to display product badges, quantities, variant swatches, and short descriptions using metafields in your Shopify theme.


🧠 What You’ll Learn

  • Display custom metafields like badges, short descriptions, and quantity.
  • Add variant color swatches that change the image and price on hover.
  • Build reusable, responsive product cards using Liquid, CSS, and JS.

đź§° Step 1: Set Up Your Metafields

In your Shopify admin, go to Settings → Custom data → Products and create the following metafields:

Name: Short description  
Namespace and key: custom.short_description  
Type: Single line text  

Name: Badge  
Namespace and key: custom.badge  
Type: Single line text  

Name: Quantity  
Namespace and key: custom.quantity  
Type: Integer  

Name: Swatch color  
Namespace and key: custom.swatch_color  
Type: Color (for Variants)
  

đź’» Step 2: Create the Product Card Section

In your theme code editor, go to Sections → Add a new section and name it zhd-product-card.liquid. Then paste this code:

{% raw %}
{% comment %}
  Suggested metafields:
  Short description - custom.short_description - Product
  Badge - custom.badge - Product
  Quantity - custom.quantity - Variant
  Swatch color - custom.swatch_color - Variant
{% endcomment %}

<style>
  .zhd-product-row { display:flex;flex-wrap:wrap;justify-content:center;gap:20px;margin:2rem auto;max-width:1200px; }
  .zhd-product-card { border:1px solid #eee;padding:1rem;text-align:center;position:relative;width:300px;background:#fff; }
  .product-badge { position:absolute;top:10px;left:10px;background:#000;color:#fff;font-size:0.8rem;padding:0.3rem 0.6rem;border-radius:4px; }
  .product-title { font-size:1.25rem;font-weight:600;margin:0.5rem 0; }
  .product-price .price { font-size:1.2rem;color:#b12704;font-weight:bold; }
  .compare-price { text-decoration:line-through;color:#888;margin-left:0.4rem;font-size:1rem; }
  .swatch { width:24px;height:24px;border-radius:50%;border:1px solid #ccc;cursor:pointer;transition:transform 0.2s; }
  .swatch:hover { transform:scale(1.1);border-color:#000; }
  .add-to-cart { background:#000;color:#fff;padding:0.5rem 1rem;margin-top:0.8rem;border:none;cursor:pointer;transition:0.3s; }
  .add-to-cart:hover { background:#444; }
</style>

<div class="zhd-product-row">
  {% for block in section.blocks %}
    {% assign product = all_products[block.settings.product] %}
    {% assign variant = product.variants.first %}
    <div class="zhd-product-card">
      <div class="product-image-wrapper">
        <img class="product-main-image" src="{{ variant.featured_image | img_url: '250x' }}" alt="{{ product.title }}">
      </div>
      <h3 class="product-title">{{ product.title }}</h3>
      <p class="product-description">{{ product.metafields.custom.short_description }}</p>
      <div class="product-price">
        <span class="price">{{ variant.price | money }}</span>
        {% if variant.compare_at_price > variant.price %}
          <span class="compare-price">{{ variant.compare_at_price | money }}</span>
        {% endif %}
      </div>
      <div class="variant-swatches">
        {% for v in product.variants %}
          <div class="swatch" style="background-color:{{ v.metafields.custom.swatch_color }};" data-image="{{ v.featured_image | img_url: '700x' }}"></div>
        {% endfor %}
      </div>
      <form method="post" action="/cart/add">
        <input type="hidden" name="id" value="{{ variant.id }}">
        <button type="submit" class="add-to-cart">Add to Cart</button>
      </form>
    </div>
  {% endfor %}
</div>

<script>
  document.addEventListener("DOMContentLoaded",function(){
    document.querySelectorAll(".zhd-product-card").forEach(card=>{
      const img=card.querySelector(".product-main-image");
      card.querySelectorAll(".swatch").forEach(s=>{
        s.addEventListener("mouseover",()=>{img.src=s.dataset.image;});
      });
    });
  });
</script>

{% schema %}
{
  "name":"ZHD Product Card",
  "settings":[],
  "blocks":[{"type":"product","name":"Product","settings":[{"type":"product","id":"product","label":"Select Product"}]}],
  "max_blocks":10,
  "presets":[{"name":"ZHD Product Card"}]
}
{% endschema %}
{% endraw %}
  

🎨 Step 3: Add Products to the Section

Open your Theme Editor (Online Store → Customize), add the “ZHD Product Card” section, and select your products in each block. Shopify will automatically show each product’s title, image, and metafields.

✨ Step 4: Test the Variant Swatches

Hover over any color swatch — the main product image and price will instantly update. This creates an interactive browsing experience for customers.

đź‘€ Final Result Preview

And that’s it! You’ve built a fully dynamic product card section that uses metafields, variant swatches, and live price updates — all with just a few lines of Liquid, CSS, and JS. 🎉

Written by Zahidul | Shopify Advanced Tutorials

Back to blog

Leave a comment