How to create color swatch for Product in Product List
How to create color swatch for Product in Product List
On my main page I have a block with a product catalog and I need to display radio buttons with colors and sizes. I'm bringing out product-variant-picker snippet from Dawn. I need to style the color buttons to match this color. For this purpose I created a metafield. The problem is that I display the label of the radio button, but due to the fact that one size has one color, the same color is displayed twice, but when you add to the cart, everything is added correctly. The problem is in the metafield output.
For example, a product has 4 colors and two sizes. That is, he has 8 options. And when I display the code below, I have 4 color buttons as it should be, but the first two are the same color and the second two are a different color. This is due to the fact that there are two variants of the same color.
//product-variant-picker
{%- unless product.has_only_default_variant -%}
<variant-radios
id="variant-radios-{{ section.id }}"
class="no-js-hidden"
data-section="{{ section.id }}"
data-url="{{ product.url }}"
{% if update_url == false %}
data-update-url="false"
{% endif %}
>
{%- for option in product.options_with_values -%}
<fieldset class="js product-form__input">
{% render 'custom-product-variant-options', product: product, option: option %}
</fieldset>
{%- endfor -%}
<script type="application/json">
{{ product.variants | json }}
</script>
</variant-radios>
{%- endunless -%}
//product-variant-options
{%- liquid
assign variants_available_arr = product.variants | map: 'available'
assign variants_option1_arr = product.variants | map: 'option1'
assign variants_option2_arr = product.variants | map: 'option2'
assign variants_option3_arr = product.variants | map: 'option3'
assign product_form_id = 'product-form-' | append: section.id
-%}
{%- for value in option.values -%}
{%- liquid
assign option_disabled = true
for option1_name in variants_option1_arr
case option.position
when 1
if variants_option1_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
assign option_disabled = false
endif
when 2
if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
assign option_disabled = false
endif
when 3
if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == product.selected_or_first_available_variant.option2 and variants_option3_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
assign option_disabled = false
endif
endcase
endfor
-%}
<input
type="radio"
id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
name="{{ option.name }}"
value="{{ value | escape }}"
form="{{ product_form_id }}"
{% if option.selected_value == value %}
checked
{% endif %}
{% if option_disabled %}
class="disabled"
{% endif %}
>
{% if option.name == 'Color' %}
<label
class="color-swatch"
style="background-color: {{ product.variants[forloop.index0].metafields.custom.color }}"
for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
>
</label>
{% else %}
<label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
{{ value }}
</label>
{% endif %}
{%- endfor -%}
Run code snippetExpand snippet
<ul
class="products-with-filter__content-products grid product-grid grid--3-col-desktop"
data-id="{{ section.id }}"
>
{%- paginate collections.all.products by section.settings.products_per_page -%}
{% for product in collections.all.products %}
<li>
...
{% render 'product-variant-picker', product: product, product_form_id: product_form_id %}
{%- render 'buy-buttons',
product: product,
product_form_id: product_form_id,
section_id: section.id,
show_pickup_availability: true
-%}
</li>
{% endfor %}
{%- endpaginate -%}
</ul>
Run code snippetExpand snippet
Desired result
What comes out
Tthis issue is happening because you need to get the variant correctly inside product-variant-options.liquid. The forloop.index0 represents the variant options not the variant itself. This causes you to refer an incorrect variant.
Try the following code, this would get the correct variant by looping through the variant options.
{%- liquid
assign variants_available_arr = product.variants | map: 'available'
assign variants_option1_arr = product.variants | map: 'option1'
assign variants_option2_arr = product.variants | map: 'option2'
assign variants_option3_arr = product.variants | map: 'option3'
assign product_form_id = 'product-form-' | append: section.id
-%}
{%- for value in option.values -%}
{%- liquid
assign option_disabled = true
for option1_name in variants_option1_arr
case option.position
when 1
if variants_option1_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
assign option_disabled = false
endif
when 2
if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
assign option_disabled = false
endif
when 3
if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == product.selected_or_first_available_variant.option2 and variants_option3_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
assign option_disabled = false
endif
endcase
endfor
-%}
{% liquid
assign variant_needed = null
for variant in product.variants
if variant.options contains value
assign variant_needed = variant
endif
endfor
%}
<input
type="radio"
id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
name="{{ option.name }}"
value="{{ value | escape }}"
form="{{ product_form_id }}"
{% if option.selected_value == value %}
checked
{% endif %}
{% if option_disabled %}
class="disabled"
{% endif %}
>
{% if option.name == 'Color' %}
<label
class="color-swatch"
style="background-color: {{ variant_needed.metafields.custom.color }}"
for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
>
</label>
{% else %}
<label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
{{ value }}
</label>
{% endif %}
{%- endfor -%}
December 30, 2023
Turbo Multi-language Translator
Make the better internet purchasing globaly
Turbosify SEO Speed Booster
5.0 (7)•Free plan available
Get better conversions by improving store loading speed
Installed
Turbo Multi-language Chat - AI Customer service in one hand
December 30, 2023