Reading swatch data in Liquid
Read swatch data from metafields to render swatches your own way. The metafields expose the same data the default widgets use, so you can build custom layouts, alternative markup, or theme-specific styling without losing parity.
Product groups live on each product. Variant swatch colors live on the shop. Payload fields are documented under public metafields.
Product groups
Section titled “Product groups”The basic pattern
Section titled “The basic pattern”{%- assign groups = product.metafields.pl_swatches.groups.value -%}
{%- if groups -%} {%- for group in groups -%} <div class="my-swatch-group"> <span class="label">{{ group.option_name }}</span> <ul> {%- for swatch in group.swatches -%} <li> <a href="{{ product.url | replace: product.handle, swatch.handle }}"> {{ swatch.name }} </a> </li> {%- endfor -%} </ul> </div> {%- endfor -%}{%- endif -%}groups is an array because a product can belong to several groups at once (for example, a Color group and a Size group). Each group carries its own option_name and swatches list.
Swatch fields
Section titled “Swatch fields”Each entry in group.swatches has these fields:
| Field | What it is |
|---|---|
handle | Shopify handle of the linked product |
name | Display name (e.g. “Black”, “Navy”) |
type | one_color, two_colors, custom_image, product_image, image_with_text, or pill |
color_one | Hex color (when type is one_color or two_colors) |
color_two | Second hex color (when type is two_colors) |
image | Image URL (when type is custom_image or image_with_text) |
out_of_stock | true or false |
Detecting the active swatch
Section titled “Detecting the active swatch”The active swatch is the one whose handle matches the current product:
{%- for swatch in group.swatches -%} {%- if swatch.handle == product.handle -%} <span class="current">{{ swatch.name }}</span> {%- else -%} <a href="{{ product.url | replace: product.handle, swatch.handle }}"> {{ swatch.name }} </a> {%- endif -%}{%- endfor -%}Variant swatches
Section titled “Variant swatches”Variant colors come from shop.metafields.pl_swatches.options. Loop the product’s options and look up each name in that object.
{%- assign options_data = shop.metafields.pl_swatches.options.value -%}{%- assign name_lookup = options_data._name_lookup -%}
{%- for option in product.options_with_values -%} {%- assign option_name = option.name | strip -%} {%- assign option_name_downcased = option_name | downcase -%} {%- assign canonical_option_name = name_lookup[option_name_downcased] | default: option_name -%} {%- assign option_config = options_data[canonical_option_name] -%} {%- if option_config == blank -%} {%- continue -%} {%- endif -%}
{%- assign value_lookup = option_config._lookup -%} <span class="label">{{ option.name }}</span> {%- for value in option.values -%} {%- assign canonical_value = value_lookup[value] | default: value -%} {%- assign swatch = option_config.values[canonical_value] -%} {%- if swatch.color_one -%} <span aria-hidden="true" style="display: inline-block; width: 1.5rem; height: 1.5rem; background: {{ swatch.color_one }};"></span> {%- endif -%} {{ value }} {%- endfor -%}{%- endfor -%}The shop object includes every option in the store. Skip names that are not on this product. See public metafields for the other fields (image, color_two, swatch_style) and how translated names are keyed.