Shopify Tutorial: Associating Product Variants with Product Images

In this tutorial I’ll be showing you how to associate product variants with product images using jQuery and Shopify’s new feature for adding unique alt tags for product images. For demonstration purposes I’m going to be modifying one of Shopify’s free themes, Radiance, but this technique will work with any theme. You can check out demos of this in action here (single option) and here (multiple options).

The screenshot below shows what the Radiance’s theme looks like initially. The first thing we’re going to do is set up the product’s variants and alt tags. After that, we hide the #thumbs <ul>. Finally, we’re going to add some Javascript to make it so that the options dropdown in the top-right corner changes the image inside the #active-wrapper div with the appropriate product image. For example, if you select “Black” for colour, #active-wrapper will show the product image with the black shirt.

Radiance theme’s default product page.

Sounds easy, right? Let’s get started!

1. Set up your product variants and product image alt tags.

The first thing you must do is match up your product’s variants with your product image’s alt tags. In order for this to work, the product’s variants must be exactly the same as the product image’s alt tags. The screenshot below shows you an example of a proper setup.

It’s important to note that you can only make a product association with one option. You can certainly have up to three options for your product (for example, I added a “Size” option here), but only one will affect what product image is shown. In step 3, you’ll see how to choose which option is tied to the product images.

variants and product image alt tags

An example of a proper variants and alt tag setup.

2. Hide the thumbnails (optional)

The next step is to hide the thumbnails with CSS. This step is optional, but to me it makes sense to hide them because the variant-selecting dropdown should be the only thing that controls what’s shown as the main image.

To do this in the Radiance theme, I simply added the existing “hidden” class to the <ul> that contains all of the thumbnails, as shown below. It’s important to still output the images (although they won’t be visible) because 1) we can pre-load the images and 2) we need to grab the ‘src’ attribute of the images when we swap the main image inside #active-wrapper.

I’m also going to change the product_img_url value inside the <img&rt; tag from ‘thumb’ to original, so that we load the biggest possible product image inside #active-wrapper. In reality you can strip out a lot more of the code below, but for the purpose of this tutorial I’m just going to keep it as is.

<ul id="thumbs" class="hidden">
  {% for image in product.images %}
     <li class="{% if forloop.first %} first{% endif %}{% if forloop.last %} last{% endif %}">
       <a class="gallery" rel="product-gallery" href="{{ image | product_img_url: 'original' }}">
          <img src="{{ image | product_img_url: 'original' }}" alt="{{ image.alt | escape }}" />
       </a>
     </li>
  {% endfor %}
</ul>

Your product page should now look like this:

No thumbnails!

2. Look for the selectCallback function

If you’re using a theme from the Shopify Theme Store, the chances are high that it is using the OptionSelector javascript. This means that the theme contains a function called selectCallback.

The selectCallback function is called whenever a user selects a different option through the options dropdown menu, and it’s used to update the variant’s price and Compare At price. Since the image-swapping needs to happen when the user selects a different option, why not place our JS in selectCallback? :D

What you can do is place the code in the Step 3 inside the selectCallback function, which is usually located in “product.liquid” or “theme.liquid”. In Radiance, it is located at the bottom of “theme.liquid”.

What if your theme does not use OptionSelector? Worry not, there are other solutions. Your theme may be using a dropdown menu or radio buttons for single-option products. In that case, you can use jQuery’s change() method instead to trigger the Javascript code in Step 3.

3. Add some code to selectCallback

Paste the code marked in blue. The first bit of Liquid goes outside of the selectCallback function. Everything below “//Swapping images JS” goes inside the selectCallback function.


{% assign option_to_match = 'Your Option Name Here' %}
{% assign option_index = 0 %}
{% for option in product.options %}
  {% if option == option_to_match %}
    {% assign option_index = forloop.index0 %}
  {% endif %}
{% endfor %}


 <script>
    var selectCallback = function(variant, selector) {
    
     //Swapping images JS
    var optionValue = variant.options[{{ option_index }}];
    var imageSrc = $("#thumbs img[alt='"+optionValue+"']").attr('src');
    if (imageSrc != 'undefined') {
      //Change '_thumb' with the image size that you are using for the thumbnails
      imageSrc = imageSrc.replace('_thumb','');
      $('#active-wrapper img').attr('src', imageSrc);
    }
    
...rest of selectCallback code

If your code does not use selectCallback, what you could do is use jQuery’s change() method to check for when the option for the dropdown is changed. The code would look something like the code below, where ‘#selector’ (marked in blue) is the id of the select dropdown or radio buttons.


{% assign option_to_match = 'Your Option Name Here' %}
{% assign option_index = 0 %}
{% for option in product.options %}
  {% if option == option_to_match %}
    {% assign option_index = forloop.index0 %}
  {% endif %}
{% endfor %}
<script>

//Swapping images JS
$('#selector').change(function() {
    var optionValue = variant.options[{{ option_index }}];
    var imageSrc = $("#thumbs img[alt='"+optionValue+"']").attr('src');
    if (imageSrc != 'undefined') {
      //Change '_thumb' with the image size that you are using for the thumbnails
      imageSrc = imageSrc.replace('_thumb','');
      $('#active-wrapper img').attr('src', imageSrc);
    }
});
</script>

First, what we need to do is set what option we want to associate with product images. This is done by changing the value of the ‘option_to_match’ variable, marked in red in the above code snippets. In this tutorial’s example, options_to_match would be “Color”, because that’s the name of the option for our variants. The Liquid code does a forloop to save the index number of the chosen option which is then used in the following Javascript snippet. Big thanks to Caro for this Liquid snippet, as without it this technique would only work for single-option products.

What the Javascript code does is it saves the variant title of the selected variant in the dropdown inside a variable, and then looks for the product image inside #thumbs that has the same alt tag as the value of the variable. Once it finds the matching product image, it takes the value of the src attribute of the matching image and places it inside the src value of the image that’s currently inside #active-wrapper.

Conclusion

That’s all there is to it! If you’re having trouble, make sure that you have set up the product alt tags and variant titles correctly, as outlined in Step 1. Please leave a comment if you have any questions or feedback!

UPDATE: I received some feedback from my peers, and it really makes no sense to limit this to one option. For example, for shirts it makes sense to have the colour and another option for size. I will be updating this article tonight to address this.

UPDATE 2: The code now supports multiple options thanks to the help of the incredible Caroline Schnapp!

UPDATE 3:Made some big fixes – sorry for the confusion guys. Also fixed a silly variable naming mistake. Thanks Czarto for catching that!

17 Responses to “Shopify Tutorial: Associating Product Variants with Product Images”

  1. Rick on January 25th, 2012

    Nice! What if each color has multiple images (e.g. back and front)?!

  2. tetchi on January 25th, 2012

    Hmm, the way it’s set up in this tutorial, you can only have one image per variant. This tutorial’s really meant to be a simple ‘base’ for variant/product-image association, so I hope someone awesome comes up with a solution for multiple images per variant :) . You could potentially set it up so that the Javascript checks for which product images’ alt tags include the variant title (instead of looking for an exact match, as it is now) and then show those images!

  3. Dave on January 26th, 2012

    Interesting approach. I guess the only thing that would keep me from using it is the fact that the alt tag of an image is meant to describe the image. In this case, Orange as the variant title and Orange as an alt tag is benign, but it will rarely be so easy with 2, 3, or more word variant titles.

    It would be awesome for the technique if the Admin would offer the ability to inject a data- attribute with whatever code you wanted, like a variants SKU for example. You could then use the same Javascript pattern, and not hurt the image search SEO.

    Any, it is progress and for n00bs with simple variants, will do just fine! Thanks for the example and for pointing out the image alt feature.

  4. tetchi on January 27th, 2012

    Hey Dave, I definitely agree with you there. I think what might be better is if I check to see if the alt tag title includes the variant title. That way, you could have the something more meaningful, like “Orange tee shirt” as the alt tag, and check to see if the variant title “Orange” is in it.

    I’ll see if I can get around to that when I get a chance! Thanks for the feedback :)

  5. thelovedone on January 29th, 2012

    Hi tetchi

    I’ve been trying to incorporate this into my site but with no success. I’m not using the Radiance theme (using the Couture theme as a base), but I tried to rework the div calls in the script to match mine. The theme does use the selectCallback function, but I still couldn’t figure out exactly where to put each snippet of code. I’ve tried it a dozen different ways, and it’s hard to tell at what point it’s not working since it doesn’t break anything. If you have time to help me out I’d really appreciate it, this is a great feature that I’d love to incorporate.

    Thanks!

  6. tetchi on January 29th, 2012

    Hmm, it’s really hard to say without seeing your shop. What’s the URL of your shop?

    EDIT: Oops, I see that your URL is there, but since it’s password-protected I won’t be able to tell what’s wrong.

  7. Brian on February 2nd, 2012

    Hi Tetchi

    I too have couture as a base and can’t seem to get it to work. I’m certain it’s something I’m doing wrong.

    I don’t see the exact callback code above your blue code in my product.liquid (other callbacks are there however), so I’m not sure exactly where to paste it. Also, I’m unsure what the appropriate name of the image id should based on this theme which uses cloudzoom.

    I have a password on my store which is: “temp”

    And here is a link to a test product with variants and alt tags all ready to go: http://goo.gl/74Xfz

    I hope you can help.
    Thanks,
    Brian

  8. Shopify Tutorial: Associating Product Variants with Product Images — Global Nerdy on February 2nd, 2012

    [...] different sizes and colors). Tetsuro Takara, one of the guys of Shopify’s Guru team, has written an article showing how you can rig up your shop’s template to show a matching photo for the curren… (for example, showing a picture of the orange version of the t-shirt when the customer has selected [...]

  9. Czarto on February 3rd, 2012

    I believe you have one line of javascript extra highlighted that shouldn’t be:

    var selectCallback = function(variant, selector) {

    Maybe I’m missing something, but I had to exclude this line of code as it already existed in my .liquid

  10. Czarto on February 3rd, 2012

    This is great stuff!

    I think in this line of the selectCallback js:
    $(‘#active-wrapper img’).attr(‘src’,imageName);

    imageName should actually be imageSrc like so:
    $(‘#active-wrapper img’).attr(‘src’,imageSrc);

  11. Czarto on February 3rd, 2012

    This is the final javascript I ended up using. Some notes:

    1. You will notice that I added a condition. If no match is found on the ALT text of them thumbnails, then it will attempt to wildcard match on the filename.
    2. I am using _small images for my thumbnails, and so during the replace I swap them to the _grande version
    3. I am grabing only the first word from my variant tile, as in my store, my variant comes out as “Black Ladies 5″, whereas I only want the color.

    if( variant && variant.title ) {
    var colourName = variant.title.replace(/^(\w+)(.*)/, ‘$1′);
    var imageSrc = $(“#thumbs img[alt='"+colourName+"']“).attr(‘src’);
    if( !imageSrc ) { // Try to match based on image src filename
    imageSrc = $(“#thumbs img[src*='"+colourName.toLowerCase()+"']“).attr(‘src’);
    }
    if (imageSrc) {
    $(‘#featured img’).attr(‘src’,imageSrc.replace(‘_small’, ‘_grande’));
    }
    }

    Hope this is helpful to someone.

  12. mkengi on February 7th, 2012

    Hi tetchi

    This is exactly what need, but i can’t get it to work. I have tried this in many different ways. I am missing something totally, but i cant figure it out. Even if i use Radiance theme to match yours (just for test). Any pointers or noob mistakes that i might be doing?

    Thanks

  13. Yasuko on February 9th, 2012

    Hi Tetchi,
    Thank you very much for this post.

    Like, thelovedone above, I’ve been trying to incorporate this into my site, but with no success. I’m using the Couture theme. I am confusing at step 3. This may be too stupid to ask, but I don’t know witch file to add those codes you mentions on step 3. In other words, where I can find “selectCallback” function…?

    If you could help me out, I would really appreciate it !!!

    Thank you!

  14. tetchi on February 9th, 2012

    ^ Hey guys, sorry I made some silly mistakes.

    1) As Czarto pointed out, I messed up on of the variable names.
    2) I forgot to include a really key line of code. Hopefully this will fix the above problems in Couture.

  15. tetchi on February 9th, 2012

    @Yasuko @Brian @mkengi shoot me an email and I’ll see what I can do! I’m just fixing up some of the code in this article, so I may not be able to get to you right away.

  16. Yasuko on February 11th, 2012

    tetchi, my site works good!
    thank you for you help!

  17. tetchi on February 12th, 2012

    @Yasuko No worries!! :)

Leave a Reply:




Comment