Shopify doesn't offer image swatches by default in the variant picker. Adding shopify variant images to color swatches enhances product presentation and boosts conversions—just like major fashion brands do.
In this blog, we’ll walk you through how to add shopify custom image swatches to color variants in Dawn Theme using Liquid.
Step-by-Step Implementation
Step 1: Open Your Shopify Store
- Log into your Shopify admin panel.
-
Go to Online Store → Themes.
- Click “Edit code” for the theme you want to modify.
Step 2: Open main-product.liquid
- Open the main-product.liquid file located in the Sections folder.
- In the main-product.liquid file, scroll to the bottom to find the schema settings, or press Ctrl + F and search for "variant_picker" to locate it quickly.

- In the variant picker settings, add a select option for image just below the button option.
{
"value": "button",
"label": "t:sections.main-product.blocks.variant_picker.settings.picker_type.options__2.label"
},
{
"value": "image",
"label": "image"
}
- Add JS code in main-product.liquid.
<style>
.hide-media{
display:none;
width:0
}
</style>
<script>
const handle = "products/" + "{{ product.handle }}" + ".js";
fetch(window.Shopify.routes.root + handle)
.then(response => response.json())
.then(product => {
const optionsToWatch = "{{settings.media_grouping_option}}".split(",");
const colorOption = product.options.find(option => optionsToWatch.includes(option.name))|| null;
if (!colorOption) {
console.log("No color options available for this product.");
return;
}
// Retrieve color values
const colorValues = colorOption.values;
// Build an object to store the starting image positions for each color
const colorImagePositions = {};
colorValues.forEach(color => {
// Find the first variant of this color and get its featured image position
const variant = product.variants.find(variant => variant.options[colorOption.position - 1] === color);
if (variant && variant.featured_media) {
colorImagePositions[color] = variant.featured_media.position;
}
});
// Sort colors based on their starting positions to calculate image ranges
const sortedColors = Object.entries(colorImagePositions).sort((a, b) => a[1] - b[1]);
// Calculate ranges and log the result
const colorImageRanges = {};
sortedColors.forEach((color, index) => {
const colorName = color[0];
const startPos = color[1];
const endPos = sortedColors[index + 1] ? sortedColors[index + 1][1] : null;
colorImageRanges[colorName] = endPos ? [startPos, endPos] : [startPos];
});
// Build an object to store image IDs grouped by color based on colorImageRanges
const colorImageIDs = {};
Object.entries(colorImageRanges).forEach(([color, range]) => {
const startPos = range[0];
const endPos = range[1] || product.media.length +1; // If no end, assume range goes to the end of the images
// Find all images within the range for this color
const imageIDs = product.media
.filter((media, index) => {
const imagePosition = index + 1; // Adjust index to be position-based
return imagePosition >= startPos && imagePosition < endPos;
})
.map(media => media.id); // Store the image ID
colorImageIDs[color] = imageIDs;
});
const mediaGallery = document.querySelector('media-gallery');
const productSection = document.querySelector(".product-variant-id")
const sectionID = "{{ section.id }}"
// Iterate over colorImageIDs to apply data-media-group based on the color ranges
Object.entries(colorImageIDs).forEach(([color, imageIDs]) => {
imageIDs.forEach(mediaID => {
// Construct the selector for each media item using sectionID and media ID
const selector = `[data-media-id="${sectionID}-${mediaID}"], [data-target="${sectionID}-${mediaID}"]`;
// Find the image <li> and add the data-media-group attribute with the color
const mediaItems = mediaGallery.querySelectorAll(`li${selector}`);
mediaItems.forEach(mediaItem=>{
mediaItem.setAttribute('data-media-group', color);
})
});
});
const showVariantImage = () => {
const variantSelects = document.querySelector('variant-selects');
// Get the currently selected color
let currentValues = Array.from(
variantSelects.querySelectorAll('select option[selected], fieldset input:checked')
).map(el => el.value);
let selectedColor = currentValues.find(value => colorImageRanges.hasOwnProperty(value));
// Show/Hide images based on selected color
mediaGallery.querySelectorAll('ul li[data-media-group]').forEach((mediaItem, index) => {
if (mediaItem.getAttribute('data-media-group') === selectedColor) {
mediaItem.classList.remove('hide-media');
} else {
mediaItem.classList.add('hide-media');
}
});
// Reinitialize the slider if needed
mediaGallery.querySelectorAll('slider-component').forEach(slider => {
slider.initPages();
});
}
showVariantImage()
// Event listener to show/hide images based on the selected color
productSection.addEventListener('change', showVariantImage);
})
.catch(error => console.error("Error fetching product data:", error));
</script>
Step 3: Add schema settings for show selected variant images.
- open settings_schema.json file from Config Folder.
- Add this following settings.
{
"name":"Media grouping option",
"settings":[
{
"type": "text",
"id": "media_grouping_option",
"label": "Media grouping option",
"default": "Color",
"info":"Group variant media together and attach the first image of each group to a variant."
},
{
"type": "paragraph",
"content": "Only one option name at a time, if you need a different option name for specific products please create a new product page template."
},
{
"type": "paragraph",
"content": "If you have a multilingual store, you can enter multiple values separated by commas: Color,Colour,Farbe,Couleur"
}
]
},
Step 4: Open product-variant-options.liquid snippet.
- Add the variant loop inside the value loop, just below this line:
- {%- for value in option.values -%}
{%- assign variant_image = null -%}
{%- for variant in product.variants -%}
{%- if variant.options contains value -%}
{%- if variant.image -%}
{%- assign variant_image = variant.image | image_url: width: 50 -%}
{%- break -%}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
- Add the image picker type option in this file, just below the button picker type.
{%- elsif picker_type == 'image' -%}
<input
type="radio"
id="{{ input_id }}"
name="{{ input_name | escape }}"
value="{{ value | escape }}"
form="{{ product_form_id }}"
{% if value.selected %}
checked
{% endif %}
{% if option_disabled %}
class="disabled"
{% endif %}
{{ input_dataset }}
>
<label for="{{ input_id }}" {% if variant_image != blank and option.name == 'Color' %} style="background-image: url({{ variant_image | img_url: '' }});height:40px;width:40px;background-size: cover;"{% else %}{{ value }} {%- endif -%}>
{{ label_unavailable }}
{% if option.name != 'Color' %}
{{ value }}
{% endif %}
</label>
Step 5: Open product-variant-picker.liquid snippet.
- Modify option loop and add picker type image.
{%- for option in product.options_with_values -%}
{%- liquid
assign swatch_count = option.values | map: 'swatch' | compact | size
assign picker_type = block.settings.picker_type
if swatch_count > 0 and block.settings.swatch_shape != 'none'
if block.settings.picker_type == 'dropdown'
assign picker_type = 'swatch_dropdown'
elsif block.settings.picker_type == 'image'
assign picker_type = 'image'
else
assign picker_type = 'swatch'
endif
endif
- Now add fieldset for image-type picker.
{%- elsif picker_type == 'image' -%}
<fieldset class="js product-form__input product-form__input--pill">
<legend class="form__label">{{ option.name }}</legend>
{% render 'product-variant-options',
product: product,
option: option,
block: block,
picker_type: picker_type
%}
</fieldset>
{%- else -%}
Step 6: Align images and variants and assign images on variants in the products.
- Go to the shopify admin panel and click on products.
- Now open a product that has variants.
- Upload product images in sequence.

- Scroll down and click on variants to assign images on variants.
Step 7: Adjust Customizer settings of the store.
- Open Customizer settings of the store
- Go to the Default product page.
- Select variant picker block under product information section.
- Now in style Click on Dropdown and select Image option.
- Check on store preview
Conclusion
Adding shopify image swatches to color variants makes product selection more visual and intuitive. It enhances user experience and gives your store a polished, professional look.
This small customization can lead to higher engagement and better conversions.