Compatibility: Dawn theme and any Shopify 2.0 FREE themes.
Most of the Shopify store owners are paying for a color swatch app. No need to do that anymore. Stop the monthly payment by following the steps below.
Are you tired of shelling out money for a color swatch app for your Shopify Dawn store? You're not alone. Many store owners have been in the same boat, searching for a cost-effective solution to add color swatches and images to their product listings. Luckily, you can now break free from those monthly payments and take control of your product presentation with our step-by-step guide.
Why Pay When You Can DIY?
Before we dive into the steps, you might wonder why you should bother with DIY solutions. Well, it's simple. Most of the color swatch apps available in the Shopify app store come with recurring monthly fees that can add up over time. By implementing your own color swatch and image solution, you can save those precious dollars for other aspects of your business.
NOTE: There are several ways to enter color swatches; it can be entered using metafields, but I don't find it convenient entering product color for each product. That is why I wrote this code. The code will also accept not only color but images as well. Multiple designs available, see images below.
Our solution goes beyond just adding color swatches; it allows you to incorporate images, providing your customers with a comprehensive view of your product variations. Whether you sell clothing, accessories, or any other items where color and design matter, this solution will elevate your Shopify Dawn store to the next level.
With this DIY Dawn color swatch and image solution, you can:
- Save money by eliminating monthly app fees.
- Provide a visually appealing and interactive shopping experience.
- Showcase your product variations effectively.
- Customize the swatch shapes, sizes, and styles to match your brand.

To start:
- Go to your Online store > Themes > Actions > Edit code
- Go to Snippet folder and create a snippet, we will name it "color-swatch".
- Open the newly created snippet and paste the code below. Click SAVE
| {% comment %} Please enter your own personalization below. Change the values inside the quotation mark ' '. {% endcomment %} {% assign swatch_size = '3vw' %} {% comment %} Change the color swatch size below.{% endcomment %} {% assign swatch_shape = 'round-edge' %} {% comment %} Change the swatch shape. Use either 'round', 'square', 'rectangle' or 'round-edge'. {% endcomment %} {% assign option_name = 'Color' %} {% comment %} Assign the name of the option you have selected. It can be 'Colour' or '색상'. {% endcomment %} {% assign picker_type = picker_type %} {% assign img_link = white | file_url %} {% assign color_file = settings.colorSwatch | strip_html | prepend: '{' | append: '}' | downcase | parse_json %} {% assign img_file = settings.colorImg | strip_html | prepend: '{' | append: '}' | downcase | parse_json %} {%- unless product.has_only_default_variant -%} {%- if picker_type == 'button' -%} <variant-radios class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}> {%- for option in product.options_with_values -%} <fieldset {% if option.name == option_name %} class="swatchComponent" style=" padding: 0;" {% else %} class="js product-form__input" style="border:none" {% endif %}> {% if option.name == option_name %} <legend class="form__label">{{ option.name }}</legend> <div class="swatchContainer"> {% assign values = option.values %} {%- for value in option.values -%} <input class="inputColor" name="{{ option.name }}" value="{{ value | escape }}" form="product-form-{{ section.id }}" type="radio" id="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}" {% if option.selected_value == value %}checked{% endif %}> <label class="labelColor" for="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}" data-color="{{value | downcase | replace: ' ', '-' }}" style=" {% case swatch_shape %} {% when 'round' %} border-radius: 50%; aspect-ratio: 1; {% when 'square' %} aspect-ratio: 1; {% when 'rectangle' %} height: calc({{swatch_size}} / 2); {% when 'round-edge' %} border-radius: 15%; aspect-ratio: 1; {% endcase %}"> </label> <div class="infoColor" > <img src="" alt="" data-info-image="{{value | downcase | replace: ' ', '-' }}" > {{value | escape}} </div> {% endfor %} </div> {% else %} <legend class="form__label">{{ option.name }}</legend> {%- for value in option.values -%} <input type="radio" id="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}" name="{{ option.name }}" value="{{ value | escape }}" form="product-form-{{ section.id }}" {% if option.selected_value == value %}checked{% endif %}> <label for="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}"> {{ value }} </label> {%- endfor -%} {% endif %} </fieldset> {% endfor -%} <script type="application/json"> {{ product.variants | json }} </script> </variant-radios> {%- else -%} <variant-selects class="no-js-hidden" data-section="{{ section.id }}" data-url="{{ product.url }}" {{ block.shopify_attributes }}> {%- for option in product.options_with_values -%} <fieldset class="swatchComponent" style=" padding: 0; {% if option.name != option_name %}display: none{% endif %}"> {% if option.name == option_name %} <legend class="form__label">{{ option.name }}</legend> <div class="swatchContainer"> {% assign values = option.values %} {%- for value in option.values -%} <input class="inputColor" name="{{ option.name }}" value="{{ value | escape }}" form="product-form-{{ section.id }}" type="radio" id="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}" {% if option.selected_value == value %}checked{% endif %}> <label class="labelColor" for="{{ section.id }}-{{ option.name }}-{{ forloop.index0 }}" data-color="{{value | downcase | replace: ' ', '-' }}" style=" {% case swatch_shape %} {% when 'round' %} border-radius: 50%; aspect-ratio: 1; {% when 'square' %} aspect-ratio: 1; {% when 'rectangle' %} height: calc({{swatch_size}} / 2); {% when 'round-edge' %} border-radius: 15%; aspect-ratio: 1; {% endcase %}"> </label> <div class="infoColor" > <img src="" alt="" data-info-image="{{value | downcase | replace: ' ', '-' }}" > {{value | escape}} </div> {% endfor %} </div> {% endif %} </fieldset> <div class="product-form__input product-form__input--dropdown" {% if option.name == option_name %}style="display: none"{% endif %}> <label class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}"> {{ option.name }} </label> <div class="select"> <select id="Option-{{ section.id }}-{{ forloop.index0 }}" class="select__select" name="options[{{ option.name | escape }}]" form="{{ product_form_id }}"> {%- for value in option.values -%} <option value="{{ value | escape }}" {% if option.selected_value == value %}selected="selected"{% endif %}> {{ value }} </option> {%- endfor -%} </select> {% render 'icon-caret' %} </div> </div> {%- endfor -%} <script type="application/json"> {{ product.variants | json }} </script> </variant-selects> {%- endif -%} {%- endunless -%} <noscript class="product-form__noscript-wrapper-{{ section.id }}"> <div class="product-form__input{% if product.has_only_default_variant %} hidden{% endif %}"> <label class="form__label" for="Variants-{{ section.id }}">{{ 'products.product.product_variants' | t }}</label> <div class="select"> <select name="id" id="Variants-{{ section.id }}" class="select__select" form="{{ product_form_id }}"> {%- for variant in product.variants -%} <option {% if variant == product.selected_or_first_available_variant %}selected="selected"{% endif %} {% if variant.available == false %}disabled{% endif %} value="{{ variant.id }}"> {{ variant.title }} {%- if variant.available == false %} - {{ 'products.product.sold_out' | t }}{% endif %} - {{ variant.price | money | strip_html }} </option> {%- endfor -%} </select> {% render 'icon-caret' %} </div> </div> </noscript> <script> const path = window.location.pathname; const variant = document.querySelector(`[data-url="${path}"]`); const imgRaw = JSON.stringify("{{img_file}}"); const imgSplit = imgRaw.split(/[,]/).map(col => col.replace(/[\"\s{}]/g, '')).map(s => s.split('.')); const imgJSON = Object.fromEntries(imgSplit); for(const img in imgJSON) { const val = `${imgJSON[img]}`; const swatchImg = variant.querySelector(`[data-color="${img}"]`); const infoImg = variant.querySelector(`[data-info-image="${img}"]`); const imgLink = '{{img_link}}'; if(swatchImg){ const imageName = `${img}.${val}`; const assetUrl = imgLink.split('?')[0] + `${imageName}`; swatchImg.style.backgroundImage = `url('${assetUrl}')`; if(infoImg) { infoImg.src = assetUrl; infoImg.style.display = 'block'; } } } console.log('This is for images:', imgJSON); const colorRaw = JSON.stringify("{{color_file}}"); const colorSplit = colorRaw.split(/[,]/).map(col => col.replace(/[\"\s{}]/g, '')).map(s => s.split(':')); const colorJSON = Object.fromEntries(colorSplit); const labels = document.querySelectorAll('.labelColor'); for(const color in colorJSON) { const val = `${colorJSON[color]}`; const swatchColor = variant.querySelector(`[data-color="${color}"]`); const values = '{{values}}'; if(swatchColor){ swatchColor.style.backgroundColor = val; } } console.log('This is for colors:', colorJSON); labels.forEach((label) => { if(label.style.backgroundColor == '' ){label.classList.add('no-background')}}) const optionName = '{{option_name}}'; const radios = variant.querySelectorAll('.inputColor'); const select = variant.querySelector(`select[name='options[${optionName}]']`); if(select) { radios.forEach((elem) => { elem.addEventListener("click", function(event) { var item = event.target.value; select.value = item ; }); }); } </script> <style> fieldset{ -webkit-touch-callout: none; /* iOS Safari */ -webkit-user-select: none; /* Safari */ -khtml-user-select: none; /* Konqueror HTML */ -moz-user-select: none; /* Old versions of Firefox */ -ms-user-select: none; /* Internet Explorer/Edge */ user-select: none; } .swatchComponent { display: flex; margin: 5% 0; box-sizing: border-box; position: relative; border: none; } .swatchContainer { display: flex; flex-wrap: wrap; justify-content: center; width: 100%; } .inputColor { display: none; } .labelColor { width: {{swatch_size}}; margin: 1%; display: flex; justify-content: center; align-items: center; cursor: pointer; overflow: hidden; transition: all .3s ease; } .no-background { background: repeating-linear-gradient(45deg, #e8e4e4, #e8e4e4 5px, #fff -2px, #fff 9px); background-position: center; background-size: 5vw; } .labelColor:hover{ transform: scale(1.1); } .infoColor { display: none; width: 100%; padding: 4%; order: 999; justify-content: flex-start; align-items: center; box-shadow: 0px 0px 5px rgb(0 0 0 / 80%); border-radius: 5px; margin-top: 20px; } .infoColor img { width: 100px; /* size of the image in the description tab */ aspect-ratio: 1; object-fit: cover; overflow: hidden; display: none; margin-right: 20px; } .inputColor:checked + .labelColor + .infoColor { display: flex; } .inputColor:checked + .labelColor { outline: 2px solid; border: 2px solid white; } </style> |
4. We have to go to the Section folder and duplicate the main-product.liquid by creating a section and name it, "product-color". Copy/paste the code from the main-product.liquid to newly created product-color.liquid.
5. Next, we will duplicate the product.json under the Template folder. Create a product template, json format, and name it, "swatch-template." Open the both the product template and copy/paste the code from the product.json to product.swatch-template.json.
6. We need to change the main-product section to product-color, as what we name our new product section.
7. Go back to the product-color.liquid under the Section folder. In the Section folder. Find and open the main-product.liquid.
Find the code {%- when 'variant_picker' -%}. Delete the code between the 'variant_picker' code and the {%- when 'buy_buttons' -%}. Then paste the code below. Click SAVE
| {% render 'color-swatch', picker_type: block.settings.picker_type %} |
8. Go to Config folder and open the settings_schema.json and paste the code before the last bracket, ']'.
| , { "name": "swatch color", "settings": [ { "type": "richtext", "id": "colorSwatch", "label": "Enter the color you want to be included in the swatch", "default": "<p> heather-black: #3f3f3f, black: #2f2f2f, heather-gray: #c5c5c5, white: #bebeb<\/p>", "info": " Use '-' if it is a two-word-color.Separate the color with comma. See default" }, { "type": "richtext", "id": "colorImg", "label": "Enter the image and then provide the name here you want to be included in the swatch", "default": "<p> heather-black.jpg, black.png, heather-gray.gif, white.png<\/p>", "info": "Use '-' if it is a two-word-color. File extension must match the file uploaded. Separate the image with comma. See default" } ] } |
9. Go to the admin view. NOTE: Your theme has to be the 'live theme' before you can see the newly created template. Click the Products below the Orders and change the theme template under the online store at the bottom right.
NOTE: Use Color Hex only. Recommended image size: 200px x 200px.
If you want to have this apply to all of your products, skip steps 5, 6, and 7, then instead of opening the newly created section, you open main-product.liquid.
You are done. All left to do is upload your images, enter your color in the theme editor and images. Make sure your image names are in lower case. See the video on how to do this.
If you have questions, you can reach me at "chat with us".
5 comments
Any chance you could update this code with the templates updates?
Variants are now used by rendering product-variant-picker and product-variant-option. I managed to adapt your code but the “disabled” state doesn’t work anymore. “Checked” are fine.
Thank you!
Kindly,
Audrey L.
Hi @Amanda,
In the new Shopify editor, the shift + tab does not work anymore
Hi @Igor Leshchencko,
Thank you (",)
Hi @Michelle,
The code works as it should. Please make sure you follow the instructions
Hi
The Shift+Tab is not working for me so the code remains the same when copied
thank you for your big work!
Hi there, the code doesn’t seem to work. Are you able to update this? :) thanks!