How can my product color option button be auto-selected as I rotate the images?

Topic summary

User wants the product image carousel and color option (variant) buttons to stay in sync: when manually rotating/swiping images, the corresponding color button should auto-select. Currently, the link works only one-way—selecting a color updates the image, but changing the image does not update the selected color.

Motivation: prevent customers from ordering the wrong color. A screenshot illustrates the gallery and color buttons.

Status: seeking implementation guidance; no solutions or technical steps provided yet. The question is how to trigger variant selection based on the currently displayed image (i.e., map each image to its color and update the option on image change). Discussion remains open.

Summarized with AI on December 15. AI used: gpt-5.

I’m wondering if there’s a way for the garment color button to be selected as the images rotate. The images jump to their respective color option when the button is selected, but it doesn’t change when the image is manually changed.

I wouldn’t want someone to order the wrong color by mistake.

2 Likes

Hi @Will408

I think you haven’t assigned images to the variants.

You have to assign correct image per variant, then it will switch automatically.

let me know if you need more help.

Thanks & Regards

I think I do have the images assigned to the variants (or thought I did). When I select a garment color option, the image changes to that color of shirt. But when I toggle between the images manually with the arrows, the selected button stays the same. I could be looking at burgundy tee but the button would remain on navy or charcoal.

I doubt any theme from the Shopify theme store does it.
This was a popular request in the forums though.

Shopify position on this functionality was that it may confuse visitors.
It should always be options → images, not images → options.

It is possible to add this functionality, but the code will be theme dependent.
Also, it would be necessary to make a “link” between images and option values as there is only one “featured image” per variant.

I don’t understand what any of that means, unfortunately. Will it need additional code to make that happen?

Yes, your theme does not support this.
It would be necessary to add some code, either in “Custom liquid” or in theme code to make it work like you want.

Also, note that it’s only one “featured” image per variant, but there can be several variant to share same image.
Say, in your case, Navy/S, Navy/M … Navy/3XL would all share the same image.

Which variant should be selected?
Or only kinda emulate “click on Navy button”?

All the different sizes share the same image per that color. I just need to have the garment color option to be automatically selected as the image is manually changed. I guess I’ll need code.

I now have a code prototype.
However, I do not 100% like the outcome.

What happens is that when you click an option value (like “navy” in your case), the theme reloads entire media gallery and re-arranges the images so that newly selected variant image is the first.

So you would not be able to scroll past second variant image.
Clicking thumbs will work, selecting different variant image in zoom will work, but actual scrolling – you’re caught in a loop.

Here is the preview link to my test store – https://cs7u7ubxh4bwc0me-23104437.shopifypreview.com/products/absolut-vodka-700ml

Here is the code – you can add a “Custom liquid” block to your “product info” section and paste the code below.
It’s hard-coded to work with the first product option for simplicity.

{% liquid
  assign variants_with_images = closest.product.variants | where: "featured_image"
  assign first_option_values = variants_with_images | map: "option1"
%}
<script>
 var option4media = option4media || {};
{% for o in first_option_values %}
  {% assign vm = variants_with_images | where: "option1", o | first %}
  option4media["{{ vm.featured_media.id }}"] = {{ o | json }};
{% endfor %}


document.addEventListener( "slideshow:select", (e)=> {
  const { target } = e;

  const productInfo = target.closest('.product-information');
  if (!productInfo) return;

  const { slide } = e.detail;
  if (!slide) return;

  mediaId = slide.querySelector('[data-media-id')?.dataset?.mediaId;
  if (!mediaId) return;

  const optionInput = productInfo.querySelector(`[value="${ option4media[mediaId] }"]:not(:checked)`);

  if (!optionInput) return;

  console.log('clicking', option4media[mediaId]);
  optionInput.dispatchEvent(new Event('change',  {bubbles:true}) );
})
</script>
1 Like

That is darn close. The buttons are selected when I scroll, but the images bounce back and forth between navy and charcoal and doesn’t go to burgundy. It does jump to burgundy when I press its button, but gets stuck in the navy and charcoal loop when I scroll past the image. I pasted the code as-is in “variant-picker.liquid”, line 107,

FYI.

Exactly:

I guess it’s possible to prevent this “re-arranging” but that would be a much more complex and intrusive change. Say, re-arrange the images so that their order is the same…

And yes, you can paste the code into theme files, but it works the same in “Custom liquid” in my store.

Update:
if you’re into editing theme code, but keep intrusion minimal, find these lines:

And replace them with this:

    assign selected_position = selected_product.media | find_index: "id", selected_variant_media.id

    for media in selected_product.media offset: selected_position
      if block_settings.hide_variants and variant_images contains media.src and sorted_media.size > 0 and media.id != selected_variant_media.id
        continue
      endif

      assign found_media = selected_product.media | where: 'id', media.id
      assign sorted_media = sorted_media | concat: found_media
    endfor
    for media in selected_product.media limit: selected_position
      if block_settings.hide_variants and variant_images contains media.src and sorted_media.size > 0 
        continue
      endif
      assign found_media = selected_product.media | where: 'id', media.id
      assign sorted_media = sorted_media | concat: found_media
    endfor

Instead of moving only the current variant image to be the first from wherever it was, the code “shifts” entire image array so that current image is the first but entire order is preserved.
You can see what it does in thumbnails.

This kinda solves the problem. Please re-visit the updated preview link above to check.

1 Like

I actually don’t have “product-media-gallery-content.liquid” in my snippets. And I’m a novice so a lot of what you said went over my head, unfortunately.

yes, right, they moved the code to this new snippet in 3.2.0.
Check blocks/_product-media-gallery.liquid around lines 85-98…

Yeah, it’s not letting me save. Something about not accepting an "‘else’ tag.

Looks like you’ve deleted some extra lines. These, at the beginning:

  assign sorted_media = '' | split: ','
  if selected_variant_media

I can’t 100% see what’s in your theme, can only guess based on my theme code and what’s available online, therefore can’t give exact line numbers.

This is the original code in my theme (I’ve added markers what to remove):

{%- liquid
  assign sorted_media = '' | split: ','
  if selected_variant_media
# --- cut from here
    assign sorted_media = sorted_media | concat: selected_product.media | where: 'id', selected_variant_media.id

    for media in selected_product.media
      if block_settings.hide_variants and variant_images contains media.src and sorted_media.size > 0
        continue
      endif

      if media.id != selected_variant_media.id
        assign found_media = selected_product.media | where: 'id', media.id
        assign sorted_media = sorted_media | concat: found_media
      endif
    endfor
# --- to here
  else
    assign sorted_media = selected_product.media
  endif
  assign has_image_drop = sorted_media | has: 'media_type', 'image'

  # Determine if we're in single column mode (carousel or grid with one column)

This is what it should become:

{%- liquid
  assign sorted_media = '' | split: ','
  if selected_variant_media
# --- start of my code paste here 
    assign selected_position = selected_product.media | find_index: "id", selected_variant_media.id

    for media in selected_product.media offset: selected_position
      if block_settings.hide_variants and variant_images contains media.src and sorted_media.size > 0 and media.id != selected_variant_media.id
        continue
      endif

      assign found_media = selected_product.media | where: 'id', media.id
      assign sorted_media = sorted_media | concat: found_media
    endfor
    for media in selected_product.media limit: selected_position
      if block_settings.hide_variants and variant_images contains media.src and sorted_media.size > 0 
        continue
      endif
      assign found_media = selected_product.media | where: 'id', media.id
      assign sorted_media = sorted_media | concat: found_media
    endfor  
# --- my code ends
  else
    assign sorted_media = selected_product.media
  endif
  assign has_image_drop = sorted_media | has: 'media_type', 'image'

  # Determine if we're in single column mode (carousel or grid with one column)
1 Like

Still didn’t work. It saved without a problem but the selected color button doesn’t change when I scroll.

1 Like

It’s password-protected?

Also – you’ve kept the initial Javascript code as well, right?

Yes on both I believe. Again, I’m a novice just trying to learn as I go.

Sharing another preview link to this code working in my test store – Absolut Vodka 700mL – BBK Market

Yours works great. Scrolls and changes highlighted button to match image.