AI generated block “product grid variants”

I’ve created a new block on my home page utilizing the AI generated function in Shopify. My theme is Craft. I prompted the AI to create a “product grid variants” to display the collection “all products” and show the variant color swatches on the product tile. Unfortunately, the color swatches do not display the colors linked, but it does show the correct amount of color variants.

I’ve checked to ensure my color variants are correct in the category metafields, and I believe I’ve done everything correctly there. Any recommendations on how to ensure the swatches will correctly display on the product tile is appreciated. Thanks!

Hi @CATCH23SWIM

The problem you’re facing is that the AI-generated code is too generic to connect with your theme’s specific color data. The code sees the variants but doesn’t know how to find the associated color hex codes or images.

The easiest and most reliable solution is to use the Craft theme’s native functionality. Instead of the AI-generated section, add a standard “Featured Collection” section to your homepage. In that section’s settings (or in Theme settings > Products > Swatches), simply ensure that “Show swatches on product cards” is enabled. This feature is designed to work perfectly with your color data out of the box.

Hope this helps!

Since no one knows what AI has generated for you, no one can help you from the outside.

Also – how your product options are set up, where the code should pull this color data from?

You can force AI to do what you want by being more specific about what you want, but this may require more knowledge that you have. :face_with_raised_eyebrow:

Thanks for the suggestion! Ive tried, and I can’t find the option anywhere in the theme settings to toggle on the color swatches. Do you think this could be the theme that doesn’t allow for the color swatches to be displayed on the product tiles?

Hi @CATCH23SWIM,

Please send the website link, I will check it for you.

Because with the current description, it is difficult to check this.

Catch23swim.com - the issue is on the home page

Go to your themes, click ... and “edit code”
Under blocks/ find this AI-generated block, copy contents and paste here using </> button.

Then someone would be able to suggest a fix.

Hi @CATCH23SWIM,
This is a common issue when Shopify AI generates code: it may set up the swatch container and loops, but it usually doesn’t include the logic to map the metafield color to the swatch background.

Check the AI-generated loop

  • Look for a code snippet like this in the section/block:
{% for variant in product.variants %}
  <span class="swatch"></span>
{% endfor %}

Often the style attribute is missing. You need to bind the metafield color to the swatch:

{% for variant in product.variants %}
  {% assign color = variant.metafields.namespace.color %}
  <span class="swatch" style="background-color: {{ color }};"></span>
{% endfor %}

{% doc %}
  @prompt
    duplicate the other AI section "product grid variants" and ensure that all the color variants are linking directly to the color category metafield for each product. There should be three color variants for the tie-front textured one piece, and five color variants for the tie-front bikini top and the staple high rise bottom. Ensure that the color swatches are displaying correctly. , fix the variant display to show the color not size variant 
{% enddoc %}
{% assign ai_gen_id = block.id | replace: '_', '' | downcase %}

{% style %}
  .ai-product-grid-variants-{{ ai_gen_id }} {
    padding: {{ block.settings.section_padding_top }}px 0 {{ block.settings.section_padding_bottom }}px;
  }

  .ai-product-grid-variants__container-{{ ai_gen_id }} {
    max-width: {{ settings.page_width }}px;
    margin: 0 auto;
    padding: 0 {{ settings.spacing_grid_horizontal }}px;
  }

  .ai-product-grid-variants__heading-{{ ai_gen_id }} {
    text-align: {{ block.settings.heading_alignment }};
    margin-bottom: {{ block.settings.heading_margin }}px;
    font-size: {{ block.settings.heading_size }}px;
    color: rgb(var(--color-foreground));
  }

  .ai-product-grid-variants__grid-{{ ai_gen_id }} {
    display: grid;
    grid-template-columns: repeat({{ block.settings.columns_desktop }}, 1fr);
    gap: {{ settings.spacing_grid_vertical }}px {{ settings.spacing_grid_horizontal }}px;
    margin-bottom: 40px;
  }

  @media screen and (max-width: 749px) {
    .ai-product-grid-variants__grid-{{ ai_gen_id }} {
      grid-template-columns: repeat({{ block.settings.columns_mobile }}, 1fr);
    }
  }

  .ai-product-card-{{ ai_gen_id }} {
    position: relative;
    background: rgb(var(--color-background));
    border-radius: {{ settings.card_corner_radius }}px;
    {% if settings.card_border_thickness > 0 %}
      border: {{ settings.card_border_thickness }}px solid rgba(var(--color-foreground), {{ settings.card_border_opacity | divided_by: 100.0 }});
    {% endif %}
    {% if settings.card_shadow_opacity > 0 %}
      box-shadow: {{ settings.card_shadow_horizontal_offset }}px {{ settings.card_shadow_vertical_offset }}px {{ settings.card_shadow_blur }}px rgba(var(--color-shadow), {{ settings.card_shadow_opacity | divided_by: 100.0 }});
    {% endif %}
    overflow: hidden;
    transition: transform 0.3s ease;
  }

  .ai-product-card-{{ ai_gen_id }}:hover {
    {% if settings.animations_hover_elements == 'vertical-lift' %}
      transform: translateY(-5px);
    {% elsif settings.animations_hover_elements == '3d-lift' %}
      transform: translateY(-5px) scale(1.02);
    {% endif %}
  }

  .ai-product-card__image-wrapper-{{ ai_gen_id }} {
    position: relative;
    width: 100%;
    aspect-ratio: {{ block.settings.image_ratio }};
    overflow: hidden;
    padding: {{ settings.card_image_padding }}px;
  }

  .ai-product-card__image-{{ ai_gen_id }} {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: {{ settings.media_radius }}px;
    transition: transform 0.3s ease;
  }

  .ai-product-card-{{ ai_gen_id }}:hover .ai-product-card__image-{{ ai_gen_id }} {
    transform: scale(1.05);
  }

  .ai-product-card__image-placeholder-{{ ai_gen_id }} {
    width: 100%;
    height: 100%;
    background-color: rgba(var(--color-foreground), 0.04);
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: {{ settings.media_radius }}px;
  }

  .ai-product-card__image-placeholder-{{ ai_gen_id }} svg {
    width: 60%;
    height: 60%;
    opacity: 0.3;
  }

  .ai-product-card__content-{{ ai_gen_id }} {
    padding: 20px;
    text-align: {{ settings.card_text_alignment }};
  }

  .ai-product-card__title-{{ ai_gen_id }} {
    font-size: 16px;
    font-weight: 500;
    margin: 0 0 8px;
    color: rgb(var(--color-foreground));
  }

  .ai-product-card__title-link-{{ ai_gen_id }} {
    text-decoration: none;
    color: inherit;
  }

  .ai-product-card__title-link-{{ ai_gen_id }}:hover {
    color: rgb(var(--color-button));
  }

  .ai-product-card__price-{{ ai_gen_id }} {
    font-size: 14px;
    margin-bottom: 12px;
    color: rgb(var(--color-foreground));
  }

  .ai-product-card__price--sale-{{ ai_gen_id }} {
    color: rgb(var(--color-button));
  }

  .ai-product-card__price--compare-{{ ai_gen_id }} {
    text-decoration: line-through;
    opacity: 0.7;
    margin-left: 8px;
  }

  .ai-product-card__variants-{{ ai_gen_id }} {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: {{ settings.card_text_alignment }};
  }

  .ai-color-swatch-{{ ai_gen_id }} {
    position: relative;
    width: {{ block.settings.swatch_size }}px;
    height: {{ block.settings.swatch_size }}px;
    border-radius: 50%;
    border: 2px solid rgba(var(--color-foreground), 0.1);
    cursor: pointer;
    transition: all 0.3s ease;
    overflow: hidden;
  }

  .ai-color-swatch-{{ ai_gen_id }}:hover {
    transform: scale(1.1);
    border-color: rgb(var(--color-button));
  }

  .ai-color-swatch__inner-{{ ai_gen_id }} {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-size: cover;
    background-position: center;
  }

  .ai-color-swatch__tooltip-{{ ai_gen_id }} {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
    z-index: 10;
  }

  .ai-color-swatch-{{ ai_gen_id }}:hover .ai-color-swatch__tooltip-{{ ai_gen_id }} {
    opacity: 1;
    visibility: visible;
  }

  .ai-product-grid-variants__empty-state-{{ ai_gen_id }} {
    text-align: center;
    padding: 60px 20px;
    color: rgba(var(--color-foreground), 0.6);
  }

  .ai-product-grid-variants__empty-state-{{ ai_gen_id }} h3 {
    margin: 0 0 8px;
    font-size: 18px;
  }

  .ai-product-grid-variants__empty-state-{{ ai_gen_id }} p {
    margin: 0;
    font-size: 14px;
  }

  @media screen and (max-width: 749px) {
    .ai-product-grid-variants__container-{{ ai_gen_id }} {
      padding: 0 {{ settings.spacing_grid_horizontal | divided_by: 2 }}px;
    }

    .ai-product-card__content-{{ ai_gen_id }} {
      padding: 16px;
    }

    .ai-color-swatch-{{ ai_gen_id }} {
      width: {{ block.settings.swatch_size | times: 0.8 }}px;
      height: {{ block.settings.swatch_size | times: 0.8 }}px;
    }
  }
{% endstyle %}

<product-grid-variants-{{ ai_gen_id }}
  class="ai-product-grid-variants-{{ ai_gen_id }} color-{{ block.settings.color_scheme }}"
  {{ block.shopify_attributes }}
>
  <div class="ai-product-grid-variants__container-{{ ai_gen_id }}">
    {% if block.settings.heading != blank %}
      <h2 class="ai-product-grid-variants__heading-{{ ai_gen_id }}">
        {{ block.settings.heading }}
      </h2>
    {% endif %}

    {% if block.settings.collection != blank and block.settings.collection.products.size > 0 %}
      <div class="ai-product-grid-variants__grid-{{ ai_gen_id }}">
        {% for product in block.settings.collection.products limit: block.settings.products_to_show %}
          <div class="ai-product-card-{{ ai_gen_id }}">
            <div class="ai-product-card__image-wrapper-{{ ai_gen_id }}">
              {% if product.featured_image %}
                <img
                  src="{{ product.featured_image | image_url: width: 600 }}"
                  alt="{{ product.featured_image.alt | escape }}"
                  class="ai-product-card__image-{{ ai_gen_id }}"
                  loading="lazy"
                  width="600"
                  height="{{ 600 | divided_by: product.featured_image.aspect_ratio | round }}"
                >
              {% else %}
                <div class="ai-product-card__image-placeholder-{{ ai_gen_id }}">
                  {{ 'product-1' | placeholder_svg_tag }}
                </div>
              {% endif %}
            </div>

            <div class="ai-product-card__content-{{ ai_gen_id }}">
              <h3 class="ai-product-card__title-{{ ai_gen_id }}">
                <a href="{{ product.url }}" class="ai-product-card__title-link-{{ ai_gen_id }}">
                  {{ product.title }}
                </a>
              </h3>

              <div class="ai-product-card__price-{{ ai_gen_id }}">
                {% if product.compare_at_price > product.price %}
                  <span class="ai-product-card__price--sale-{{ ai_gen_id }}">
                    {{ product.price | money }}
                  </span>
                  <span class="ai-product-card__price--compare-{{ ai_gen_id }}">
                    {{ product.compare_at_price | money }}
                  </span>
                {% else %}
                  {{ product.price | money }}
                {% endif %}
              </div>

              {% comment %}Color variants only - filter out size variants{% endcomment %}
              {% if block.settings.show_color_variants %}
                <div class="ai-product-card__variants-{{ ai_gen_id }}">
                  {% liquid
                    assign color_variants = ''
                    assign color_option_index = -1
                    
                    for option in product.options_with_values
                      assign option_name_lower = option.name | downcase
                      if option_name_lower contains 'color' or option_name_lower contains 'colour'
                        assign color_option_index = forloop.index0
                        break
                      endif
                    endfor
                    
                    if color_option_index >= 0
                      assign seen_colors = ''
                      for variant in product.variants
                        assign variant_color = variant.options[color_option_index]
                        unless seen_colors contains variant_color
                          assign seen_colors = seen_colors | append: variant_color | append: ','
                          assign color_variants = color_variants | append: variant.id | append: ','
                        endunless
                      endfor
                      assign color_variant_ids = color_variants | split: ','
                    endif
                  %}

                  {% if color_option_index >= 0 and color_variant_ids.size > 0 %}
                    {% for variant_id in color_variant_ids limit: 5 %}
                      {% if variant_id != blank %}
                        {% assign variant = product.variants[variant_id] %}
                        {% for v in product.variants %}
                          {% if v.id == variant_id %}
                            {% assign variant = v %}
                            {% break %}
                          {% endif %}
                        {% endfor %}

                        {% liquid
                          assign color_name = variant.options[color_option_index]
                          assign color_value = variant.metafields.custom.color_hex.value
                          assign color_category = variant.metafields.custom.color_category.value
                          assign variant_image = variant.image
                          
                          if color_category != blank
                            assign color_name = color_category
                          endif
                          
                          if color_value == blank
                            case color_name | downcase
                              when 'black'
                                assign color_value = '#000000'
                              when 'white'
                                assign color_value = '#ffffff'
                              when 'red'
                                assign color_value = '#ff0000'
                              when 'blue'
                                assign color_value = '#0000ff'
                              when 'green'
                                assign color_value = '#008000'
                              when 'pink'
                                assign color_value = '#ffc0cb'
                              when 'purple'
                                assign color_value = '#800080'
                              when 'yellow'
                                assign color_value = '#ffff00'
                              when 'orange'
                                assign color_value = '#ffa500'
                              when 'brown'
                                assign color_value = '#a52a2a'
                              when 'grey', 'gray'
                                assign color_value = '#808080'
                              when 'navy'
                                assign color_value = '#000080'
                              when 'beige'
                                assign color_value = '#f5f5dc'
                              else
                                assign color_value = '#cccccc'
                            endcase
                          endif
                          
                          assign variant_url = product.url | append: '?variant=' | append: variant.id
                        %}

                        <a
                          href="{{ variant_url }}"
                          class="ai-color-swatch-{{ ai_gen_id }}"
                          title="{{ color_name | escape }}"
                          data-variant-id="{{ variant.id }}"
                          data-color="{{ color_name | escape }}"
                        >
                          <div
                            class="ai-color-swatch__inner-{{ ai_gen_id }}"
                            style="
                              {% if variant_image %}
                                background-image: url('{{ variant_image | image_url: width: 100 }}');
                              {% else %}
                                background-color: {{ color_value }};
                              {% endif %}
                            "
                          ></div>
                          <div class="ai-color-swatch__tooltip-{{ ai_gen_id }}">
                            {{ color_name }}
                          </div>
                        </a>
                      {% endif %}
                    {% endfor %}
                  {% endif %}
                </div>
              {% endif %}
            </div>
          </div>
        {% endfor %}
      </div>
    {% else %}
      <div class="ai-product-grid-variants__empty-state-{{ ai_gen_id }}">
        <h3>No products found</h3>
        <p>Select a collection to display products with color variants</p>
      </div>
    {% endif %}
  </div>
</product-grid-variants-{{ ai_gen_id }}>

<script>
  (function() {
    class ProductGridVariants{{ ai_gen_id }} extends HTMLElement {
      constructor() {
        super();
      }

      connectedCallback() {
        this.setupColorSwatches();
      }

      setupColorSwatches() {
        const swatches = this.querySelectorAll('.ai-color-swatch-{{ ai_gen_id }}');
        
        swatches.forEach(swatch => {
          swatch.addEventListener('click', (e) => {
            e.preventDefault();
            const url = swatch.getAttribute('href');
            if (url) {
              window.location.href = url;
            }
          });

          swatch.addEventListener('mouseenter', () => {
            const productCard = swatch.closest('.ai-product-card-{{ ai_gen_id }}');
            const variantId = swatch.dataset.variantId;
            
            if (productCard && variantId) {
              this.updateProductImage(productCard, variantId);
            }
          });
        });
      }

      updateProductImage(productCard, variantId) {
        const image = productCard.querySelector('.ai-product-card__image-{{ ai_gen_id }}');
        const swatch = productCard.querySelector(`[data-variant-id="${variantId}"]`);
        
        if (image && swatch) {
          const swatchInner = swatch.querySelector('.ai-color-swatch__inner-{{ ai_gen_id }}');
          const backgroundImage = swatchInner.style.backgroundImage;
          
          if (backgroundImage && backgroundImage.includes('url(')) {
            const imageUrl = backgroundImage.match(/url\(['"]?([^'"]+)['"]?\)/)[1];
            if (imageUrl) {
              const newImageUrl = imageUrl.replace(/width=\d+/, 'width=600');
              image.src = newImageUrl;
            }
          }
        }
      }
    }

    customElements.define('product-grid-variants-{{ ai_gen_id }}', ProductGridVariants{{ ai_gen_id }});
  })();
</script>

{% schema %}
{
  "name": "Product grid variants",
  "tag": null,
  "settings": [
    {
      "type": "header",
      "content": "Content"
    },
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Featured products"
    },
    {
      "type": "select",
      "id": "heading_alignment",
      "label": "Heading alignment",
      "options": [
        {
          "value": "left",
          "label": "Left"
        },
        {
          "value": "center",
          "label": "Center"
        },
        {
          "value": "right",
          "label": "Right"
        }
      ],
      "default": "center"
    },
    {
      "type": "collection",
      "id": "collection",
      "label": "Collection"
    },
    {
      "type": "range",
      "id": "products_to_show",
      "min": 2,
      "max": 12,
      "step": 1,
      "label": "Products to show",
      "default": 6
    },
    {
      "type": "checkbox",
      "id": "show_color_variants",
      "label": "Show color variants",
      "default": true
    },
    {
      "type": "header",
      "content": "Layout"
    },
    {
      "type": "range",
      "id": "columns_desktop",
      "min": 2,
      "max": 4,
      "step": 1,
      "label": "Columns on desktop",
      "default": 3
    },
    {
      "type": "select",
      "id": "columns_mobile",
      "label": "Columns on mobile",
      "options": [
        {
          "value": "1",
          "label": "1"
        },
        {
          "value": "2",
          "label": "2"
        }
      ],
      "default": "2"
    },
    {
      "type": "select",
      "id": "image_ratio",
      "label": "Image ratio",
      "options": [
        {
          "value": "1/1",
          "label": "Square"
        },
        {
          "value": "3/4",
          "label": "Portrait"
        },
        {
          "value": "4/3",
          "label": "Landscape"
        }
      ],
      "default": "3/4"
    },
    {
      "type": "header",
      "content": "Color swatches"
    },
    {
      "type": "range",
      "id": "swatch_size",
      "min": 20,
      "max": 40,
      "step": 2,
      "unit": "px",
      "label": "Swatch size",
      "default": 28
    },
    {
      "type": "header",
      "content": "Style"
    },
    {
      "type": "color_scheme",
      "id": "color_scheme",
      "label": "Color scheme",
      "default": "background-1"
    },
    {
      "type": "range",
      "id": "heading_size",
      "min": 16,
      "max": 48,
      "step": 2,
      "unit": "px",
      "label": "Heading size",
      "default": 32
    },
    {
      "type": "range",
      "id": "heading_margin",
      "min": 0,
      "max": 60,
      "step": 4,
      "unit": "px",
      "label": "Heading margin bottom",
      "default": 32
    },
    {
      "type": "header",
      "content": "Section padding"
    },
    {
      "type": "range",
      "id": "section_padding_top",
      "min": 0,
      "max": 100,
      "step": 4,
      "unit": "px",
      "label": "Top padding",
      "default": 40
    },
    {
      "type": "range",
      "id": "section_padding_bottom",
      "min": 0,
      "max": 100,
      "step": 4,
      "unit": "px",
      "label": "Bottom padding",
      "default": 40
    }
  ],
  "presets": [
    {
      "name": "Product grid variants"
    }
  ]
}
{% endschema %}

Looking at your Shopify Liquid code, I can see the issue with the color swatches not displaying correctly. The problem is in how the code is trying to access the color metafields and find the correct variants. Here is the updated code that you can use.

{% doc %}
  @prompt
    duplicate the other AI section "product grid variants" and ensure that all the color variants are linking directly to the color category metafield for each product. There should be three color variants for the tie-front textured one piece, and five color variants for the tie-front bikini top and the staple high rise bottom. Ensure that the color swatches are displaying correctly. , fix the variant display to show the color not size variant 
{% enddoc %}
{% assign ai_gen_id = block.id | replace: '_', '' | downcase %}

{% style %}
  .ai-product-grid-variants-{{ ai_gen_id }} {
    padding: {{ block.settings.section_padding_top }}px 0 {{ block.settings.section_padding_bottom }}px;
  }

  .ai-product-grid-variants__container-{{ ai_gen_id }} {
    max-width: {{ settings.page_width }}px;
    margin: 0 auto;
    padding: 0 {{ settings.spacing_grid_horizontal }}px;
  }

  .ai-product-grid-variants__heading-{{ ai_gen_id }} {
    text-align: {{ block.settings.heading_alignment }};
    margin-bottom: {{ block.settings.heading_margin }}px;
    font-size: {{ block.settings.heading_size }}px;
    color: rgb(var(--color-foreground));
  }

  .ai-product-grid-variants__grid-{{ ai_gen_id }} {
    display: grid;
    grid-template-columns: repeat({{ block.settings.columns_desktop }}, 1fr);
    gap: {{ settings.spacing_grid_vertical }}px {{ settings.spacing_grid_horizontal }}px;
    margin-bottom: 40px;
  }

  @media screen and (max-width: 749px) {
    .ai-product-grid-variants__grid-{{ ai_gen_id }} {
      grid-template-columns: repeat({{ block.settings.columns_mobile }}, 1fr);
    }
  }

  .ai-product-card-{{ ai_gen_id }} {
    position: relative;
    background: rgb(var(--color-background));
    border-radius: {{ settings.card_corner_radius }}px;
    {% if settings.card_border_thickness > 0 %}
      border: {{ settings.card_border_thickness }}px solid rgba(var(--color-foreground), {{ settings.card_border_opacity | divided_by: 100.0 }});
    {% endif %}
    {% if settings.card_shadow_opacity > 0 %}
      box-shadow: {{ settings.card_shadow_horizontal_offset }}px {{ settings.card_shadow_vertical_offset }}px {{ settings.card_shadow_blur }}px rgba(var(--color-shadow), {{ settings.card_shadow_opacity | divided_by: 100.0 }});
    {% endif %}
    overflow: hidden;
    transition: transform 0.3s ease;
  }

  .ai-product-card-{{ ai_gen_id }}:hover {
    {% if settings.animations_hover_elements == 'vertical-lift' %}
      transform: translateY(-5px);
    {% elsif settings.animations_hover_elements == '3d-lift' %}
      transform: translateY(-5px) scale(1.02);
    {% endif %}
  }

  .ai-product-card__image-wrapper-{{ ai_gen_id }} {
    position: relative;
    width: 100%;
    aspect-ratio: {{ block.settings.image_ratio }};
    overflow: hidden;
    padding: {{ settings.card_image_padding }}px;
  }

  .ai-product-card__image-{{ ai_gen_id }} {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: {{ settings.media_radius }}px;
    transition: transform 0.3s ease;
  }

  .ai-product-card-{{ ai_gen_id }}:hover .ai-product-card__image-{{ ai_gen_id }} {
    transform: scale(1.05);
  }

  .ai-product-card__image-placeholder-{{ ai_gen_id }} {
    width: 100%;
    height: 100%;
    background-color: rgba(var(--color-foreground), 0.04);
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: {{ settings.media_radius }}px;
  }

  .ai-product-card__image-placeholder-{{ ai_gen_id }} svg {
    width: 60%;
    height: 60%;
    opacity: 0.3;
  }

  .ai-product-card__content-{{ ai_gen_id }} {
    padding: 20px;
    text-align: {{ settings.card_text_alignment }};
  }

  .ai-product-card__title-{{ ai_gen_id }} {
    font-size: 16px;
    font-weight: 500;
    margin: 0 0 8px;
    color: rgb(var(--color-foreground));
  }

  .ai-product-card__title-link-{{ ai_gen_id }} {
    text-decoration: none;
    color: inherit;
  }

  .ai-product-card__title-link-{{ ai_gen_id }}:hover {
    color: rgb(var(--color-button));
  }

  .ai-product-card__price-{{ ai_gen_id }} {
    font-size: 14px;
    margin-bottom: 12px;
    color: rgb(var(--color-foreground));
  }

  .ai-product-card__price--sale-{{ ai_gen_id }} {
    color: rgb(var(--color-button));
  }

  .ai-product-card__price--compare-{{ ai_gen_id }} {
    text-decoration: line-through;
    opacity: 0.7;
    margin-left: 8px;
  }

  .ai-product-card__variants-{{ ai_gen_id }} {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: {{ settings.card_text_alignment }};
  }

  .ai-color-swatch-{{ ai_gen_id }} {
    position: relative;
    width: {{ block.settings.swatch_size }}px;
    height: {{ block.settings.swatch_size }}px;
    border-radius: 50%;
    border: 2px solid rgba(var(--color-foreground), 0.1);
    cursor: pointer;
    transition: all 0.3s ease;
    overflow: hidden;
  }

  .ai-color-swatch-{{ ai_gen_id }}:hover {
    transform: scale(1.1);
    border-color: rgb(var(--color-button));
  }

  .ai-color-swatch__inner-{{ ai_gen_id }} {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-size: cover;
    background-position: center;
  }

  .ai-color-swatch__tooltip-{{ ai_gen_id }} {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: rgb(var(--color-foreground));
    color: rgb(var(--color-background));
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
    z-index: 10;
  }

  .ai-color-swatch-{{ ai_gen_id }}:hover .ai-color-swatch__tooltip-{{ ai_gen_id }} {
    opacity: 1;
    visibility: visible;
  }

  .ai-product-grid-variants__empty-state-{{ ai_gen_id }} {
    text-align: center;
    padding: 60px 20px;
    color: rgba(var(--color-foreground), 0.6);
  }

  .ai-product-grid-variants__empty-state-{{ ai_gen_id }} h3 {
    margin: 0 0 8px;
    font-size: 18px;
  }

  .ai-product-grid-variants__empty-state-{{ ai_gen_id }} p {
    margin: 0;
    font-size: 14px;
  }

  @media screen and (max-width: 749px) {
    .ai-product-grid-variants__container-{{ ai_gen_id }} {
      padding: 0 {{ settings.spacing_grid_horizontal | divided_by: 2 }}px;
    }

    .ai-product-card__content-{{ ai_gen_id }} {
      padding: 16px;
    }

    .ai-color-swatch-{{ ai_gen_id }} {
      width: {{ block.settings.swatch_size | times: 0.8 }}px;
      height: {{ block.settings.swatch_size | times: 0.8 }}px;
    }
  }
{% endstyle %}

<product-grid-variants-{{ ai_gen_id }}
  class="ai-product-grid-variants-{{ ai_gen_id }} color-{{ block.settings.color_scheme }}"
  {{ block.shopify_attributes }}
>
  <div class="ai-product-grid-variants__container-{{ ai_gen_id }}">
    {% if block.settings.heading != blank %}
      <h2 class="ai-product-grid-variants__heading-{{ ai_gen_id }}">
        {{ block.settings.heading }}
      </h2>
    {% endif %}

    {% if block.settings.collection != blank and block.settings.collection.products.size > 0 %}
      <div class="ai-product-grid-variants__grid-{{ ai_gen_id }}">
        {% for product in block.settings.collection.products limit: block.settings.products_to_show %}
          <div class="ai-product-card-{{ ai_gen_id }}">
            <div class="ai-product-card__image-wrapper-{{ ai_gen_id }}">
              {% if product.featured_image %}
                <img
                  src="{{ product.featured_image | image_url: width: 600 }}"
                  alt="{{ product.featured_image.alt | escape }}"
                  class="ai-product-card__image-{{ ai_gen_id }}"
                  loading="lazy"
                  width="600"
                  height="{{ 600 | divided_by: product.featured_image.aspect_ratio | round }}"
                >
              {% else %}
                <div class="ai-product-card__image-placeholder-{{ ai_gen_id }}">
                  {{ 'product-1' | placeholder_svg_tag }}
                </div>
              {% endif %}
            </div>

            <div class="ai-product-card__content-{{ ai_gen_id }}">
              <h3 class="ai-product-card__title-{{ ai_gen_id }}">
                <a href="{{ product.url }}" class="ai-product-card__title-link-{{ ai_gen_id }}">
                  {{ product.title }}
                </a>
              </h3>

              <div class="ai-product-card__price-{{ ai_gen_id }}">
                {% if product.compare_at_price > product.price %}
                  <span class="ai-product-card__price--sale-{{ ai_gen_id }}">
                    {{ product.price | money }}
                  </span>
                  <span class="ai-product-card__price--compare-{{ ai_gen_id }}">
                    {{ product.compare_at_price | money }}
                  </span>
                {% else %}
                  {{ product.price | money }}
                {% endif %}
              </div>

              {% comment %}Color variants only - improved logic{% endcomment %}
              {% if block.settings.show_color_variants %}
                <div class="ai-product-card__variants-{{ ai_gen_id }}">
                  {% liquid
                    assign color_option_index = -1
                    
                    # Find the color option index
                    for option in product.options_with_values
                      assign option_name_lower = option.name | downcase
                      if option_name_lower contains 'color' or option_name_lower contains 'colour'
                        assign color_option_index = forloop.index0
                        break
                      endif
                    endfor
                    
                    # If we found a color option, get unique color variants
                    if color_option_index >= 0
                      assign unique_colors = ''
                      assign color_variants_array = ''
                      
                      for variant in product.variants
                        if variant.available
                          assign variant_color = variant.options[color_option_index] | strip
                          unless unique_colors contains variant_color
                            assign unique_colors = unique_colors | append: variant_color | append: '|'
                            assign color_variants_array = color_variants_array | append: variant.id | append: ','
                          endunless
                        endif
                      endfor
                      
                      assign color_variant_ids = color_variants_array | split: ','
                    endif
                  %}

                  {% if color_option_index >= 0 and color_variant_ids.size > 0 %}
                    {% for variant_id_str in color_variant_ids limit: 5 %}
                      {% if variant_id_str != blank %}
                        {% assign variant_id = variant_id_str | plus: 0 %}
                        {% assign current_variant = null %}
                        
                        {% comment %}Find the actual variant object{% endcomment %}
                        {% for variant in product.variants %}
                          {% if variant.id == variant_id %}
                            {% assign current_variant = variant %}
                            {% break %}
                          {% endif %}
                        {% endfor %}

                        {% if current_variant %}
                          {% liquid
                            assign color_name = current_variant.options[color_option_index] | strip
                            assign color_hex = current_variant.metafields.custom.color_hex.value
                            assign color_category = current_variant.metafields.custom.color_category.value
                            assign variant_image = current_variant.image
                            
                            # Use color_category if available, otherwise use the variant option
                            if color_category != blank
                              assign display_color_name = color_category
                            else
                              assign display_color_name = color_name
                            endif
                            
                            # If no hex color is set, try to determine from name
                            if color_hex == blank
                              assign color_name_lower = display_color_name | downcase
                              case color_name_lower
                                when 'black'
                                  assign color_hex = '#000000'
                                when 'white'
                                  assign color_hex = '#ffffff'
                                when 'red'
                                  assign color_hex = '#dc2626'
                                when 'blue'
                                  assign color_hex = '#2563eb'
                                when 'navy'
                                  assign color_hex = '#1e3a8a'
                                when 'green'
                                  assign color_hex = '#16a34a'
                                when 'pink'
                                  assign color_hex = '#ec4899'
                                when 'purple'
                                  assign color_hex = '#9333ea'
                                when 'yellow'
                                  assign color_hex = '#eab308'
                                when 'orange'
                                  assign color_hex = '#ea580c'
                                when 'brown'
                                  assign color_hex = '#a16207'
                                when 'grey', 'gray'
                                  assign color_hex = '#6b7280'
                                when 'beige'
                                  assign color_hex = '#f5f5dc'
                                when 'tan'
                                  assign color_hex = '#d2b48c'
                                when 'cream'
                                  assign color_hex = '#fffdd0'
                                else
                                  assign color_hex = '#9ca3af'
                              endcase
                            endif
                            
                            assign variant_url = product.url | append: '?variant=' | append: current_variant.id
                          %}

                          <a
                            href="{{ variant_url }}"
                            class="ai-color-swatch-{{ ai_gen_id }}"
                            title="{{ display_color_name | escape }}"
                            data-variant-id="{{ current_variant.id }}"
                            data-color="{{ display_color_name | escape }}"
                          >
                            <div
                              class="ai-color-swatch__inner-{{ ai_gen_id }}"
                              style="
                                {% if variant_image %}
                                  background-image: url('{{ variant_image | image_url: width: 100 }}');
                                {% else %}
                                  background-color: {{ color_hex }};
                                {% endif %}
                              "
                            ></div>
                            <div class="ai-color-swatch__tooltip-{{ ai_gen_id }}">
                              {{ display_color_name }}
                            </div>
                          </a>
                        {% endif %}
                      {% endif %}
                    {% endfor %}
                  {% endif %}
                </div>
              {% endif %}
            </div>
          </div>
        {% endfor %}
      </div>
    {% else %}
      <div class="ai-product-grid-variants__empty-state-{{ ai_gen_id }}">
        <h3>No products found</h3>
        <p>Select a collection to display products with color variants</p>
      </div>
    {% endif %}
  </div>
</product-grid-variants-{{ ai_gen_id }}>

<script>
  (function() {
    class ProductGridVariants{{ ai_gen_id }} extends HTMLElement {
      constructor() {
        super();
      }

      connectedCallback() {
        this.setupColorSwatches();
      }

      setupColorSwatches() {
        const swatches = this.querySelectorAll('.ai-color-swatch-{{ ai_gen_id }}');
        
        swatches.forEach(swatch => {
          swatch.addEventListener('click', (e) => {
            e.preventDefault();
            const url = swatch.getAttribute('href');
            if (url) {
              window.location.href = url;
            }
          });

          swatch.addEventListener('mouseenter', () => {
            const productCard = swatch.closest('.ai-product-card-{{ ai_gen_id }}');
            const variantId = swatch.dataset.variantId;
            
            if (productCard && variantId) {
              this.updateProductImage(productCard, variantId);
            }
          });
        });
      }

      updateProductImage(productCard, variantId) {
        const image = productCard.querySelector('.ai-product-card__image-{{ ai_gen_id }}');
        const swatch = productCard.querySelector(`[data-variant-id="${variantId}"]`);
        
        if (image && swatch) {
          const swatchInner = swatch.querySelector('.ai-color-swatch__inner-{{ ai_gen_id }}');
          const backgroundImage = swatchInner.style.backgroundImage;
          
          if (backgroundImage && backgroundImage.includes('url(')) {
            const imageUrl = backgroundImage.match(/url\(['"]?([^'"]+)['"]?\)/)[1];
            if (imageUrl) {
              const newImageUrl = imageUrl.replace(/width=\d+/, 'width=600');
              image.src = newImageUrl;
            }
          }
        }
      }
    }

    customElements.define('product-grid-variants-{{ ai_gen_id }}', ProductGridVariants{{ ai_gen_id }});
  })();
</script>

{% schema %}
{
  "name": "Product grid variants",
  "tag": null,
  "settings": [
    {
      "type": "header",
      "content": "Content"
    },
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Featured products"
    },
    {
      "type": "select",
      "id": "heading_alignment",
      "label": "Heading alignment",
      "options": [
        {
          "value": "left",
          "label": "Left"
        },
        {
          "value": "center",
          "label": "Center"
        },
        {
          "value": "right",
          "label": "Right"
        }
      ],
      "default": "center"
    },
    {
      "type": "collection",
      "id": "collection",
      "label": "Collection"
    },
    {
      "type": "range",
      "id": "products_to_show",
      "min": 2,
      "max": 12,
      "step": 1,
      "label": "Products to show",
      "default": 6
    },
    {
      "type": "checkbox",
      "id": "show_color_variants",
      "label": "Show color variants",
      "default": true
    },
    {
      "type": "header",
      "content": "Layout"
    },
    {
      "type": "range",
      "id": "columns_desktop",
      "min": 2,
      "max": 4,
      "step": 1,
      "label": "Columns on desktop",
      "default": 3
    },
    {
      "type": "select",
      "id": "columns_mobile",
      "label": "Columns on mobile",
      "options": [
        {
          "value": "1",
          "label": "1"
        },
        {
          "value": "2",
          "label": "2"
        }
      ],
      "default": "2"
    },
    {
      "type": "select",
      "id": "image_ratio",
      "label": "Image ratio",
      "options": [
        {
          "value": "1/1",
          "label": "Square"
        },
        {
          "value": "3/4",
          "label": "Portrait"
        },
        {
          "value": "4/3",
          "label": "Landscape"
        }
      ],
      "default": "3/4"
    },
    {
      "type": "header",
      "content": "Color swatches"
    },
    {
      "type": "range",
      "id": "swatch_size",
      "min": 20,
      "max": 40,
      "step": 2,
      "unit": "px",
      "label": "Swatch size",
      "default": 28
    },
    {
      "type": "header",
      "content": "Style"
    },
    {
      "type": "color_scheme",
      "id": "color_scheme",
      "label": "Color scheme",
      "default": "background-1"
    },
    {
      "type": "range",
      "id": "heading_size",
      "min": 16,
      "max": 48,
      "step": 2,
      "unit": "px",
      "label": "Heading size",
      "default": 32
    },
    {
      "type": "range",
      "id": "heading_margin",
      "min": 0,
      "max": 60,
      "step": 4,
      "unit": "px",
      "label": "Heading margin bottom",
      "default": 32
    },
    {
      "type": "header",
      "content": "Section padding"
    },
    {
      "type": "range",
      "id": "section_padding_top",
      "min": 0,
      "max": 100,
      "step": 4,
      "unit": "px",
      "label": "Top padding",
      "default": 40
    },
    {
      "type": "range",
      "id": "section_padding_bottom",
      "min": 0,
      "max": 100,
      "step": 4,
      "unit": "px",
      "label": "Bottom padding",
      "default": 40
    }
  ],
  "presets": [
    {
      "name": "Product grid variants"
    }
  ]
}
{% endschema %}

What to Check in Your Shopify Admin:

  1. Metafield Names: Ensure your metafields are named exactly:

    • custom.color_category (for display name)

    • custom.color_hex (for color values)

  2. Metafield Scope: Make sure these metafields are set on Product Variants, not just products.

  3. Product Options: Verify your products have a “Color” option (case-insensitive).

Please let me know if this works for you!.

Best,

Daniel

Hi Daniel,

Thanks for adjusting the issues with the code! I’ve applied the changes and checked the recommend shopify admin steps and I am still not seeing the colors displayed correctly. Are there any additional steps that you would recommend?

Hey @CATCH23SWIM,

Thanks for sharing the update. The only thing is highly recommend is to prompt to Shopify ai in a way that tool might read the all classes of the variant/color picker.

Or if you could share the collab code in the p/m then I can take a look into it.

Thanks

Hello,

Thanks so much for offering. I’ve sent you an email to connect for the code!

Sorry, I don’t receive it yet.