Shopify Horizon: Show Only Selected Variant Images

Show only the selected variant's images in Shopify Horizon, several photos per colour, with alt text and one free Custom Liquid block. No app or Plus needed.

By AjayCodeWiz · August 2, 2026 · 12 min read

The problem: you pick a colour in Horizon and the other photos stay

A merchant asked about this on the Shopify Community. They run the Horizon theme, and they wanted the product gallery to react to the colour a shopper picks.

The goal is simple to describe. Click Black, see only the Black photos. Click White, see only the White photos. No paid app. No Shopify Plus. A free solution that works on Horizon.

What actually happens on Horizon out of the box is different. You assign a photo to the Black variant, and clicking Black jumps to that one photo. But the White photos are still sitting in the gallery. So a shopper on Black scrolls straight into White images, which looks broken and costs you the sale.

I reproduced it on a Horizon test store. Here the Black variant is selected, yet the White images are still in the gallery.

Horizon product gallery with Black selected but White images still showingHorizon product gallery with Black selected but White images still showing

Horizon has no setting that filters a colour's full set of images. To understand why, and to fix it, it helps to know what Horizon is actually doing when you click a variant.

Why Horizon does not hide the other images

Every variant in Shopify can have exactly one assigned image. That is the image Shopify swaps to when the variant is selected.

Horizon respects that. Click a colour and the gallery moves the single image you assigned to that variant to the front. That part works as designed.

The problem is everything else in the gallery. A product page usually has more than one photo per colour. A second angle. A lifestyle shot. A close-up of the fabric. A size chart. Shopify has no concept of "these five images belong to Black." It only knows about the one assigned image.

So every image that is not a variant's assigned image is treated as shared. Shared images show for every colour, all the time. That is why your White photos still appear when Black is selected. To Shopify they are not White photos. They are just photos on the product.

Once you see it that way, the fix becomes obvious. You cannot ask Shopify to filter by colour, because Shopify does not know which colour most images belong to. You have to tell it, and then hide the ones that do not match.

The built-in toggle, and exactly where it stops

Before the code, there is a native setting worth knowing about, because for some stores it is all you need.

Open the theme editor on a product page, select the Product media block, and check that Hide unselected variant media is switched on. A fresh Horizon 4.3.0 install has it on in the default product template, but a template you made earlier may have it off. With it on, Horizon removes the images assigned to the other variants. Click Black and White's assigned image is gone from the gallery.

Horizon theme editor with the Product media block selected and the Hide unselected variant media toggle switched onHorizon theme editor with the Product media block selected and the Hide unselected variant media toggle switched on

That toggle only hides the one image assigned to each other variant. Every unassigned image, the second angle, the lifestyle shot, the size chart, still counts as shared and still shows for every colour.

So the built-in toggle gets you one clean image per colour. If that is your setup, you are done and you do not need any code. If you have several images per colour, the toggle is not enough, and you need the small block further down.

How to add variant images on Shopify

Both the toggle and the fix below work best when each colour has its photo assigned in the admin. These are the steps from Shopify's Help Center:

  • Go to Products and click the product.
  • In the Variants section, click the image icon next to the variant.
  • Select one of the product's images, or click Add image to upload a new one.
  • Click Done, then Save.

Shopify admin product page, Variants section, with the image icon next to the Black variant highlighted and the image picker openShopify admin product page, Variants section, with the image icon next to the Black variant highlighted and the image picker open

To do several variants at once, tick their boxes in the Variants section, open the menu with the three dots, and choose Add images. When the ticked variants already have images, the same menu shows Edit images instead, next to Remove images.

Variants section with several variants ticked and the three-dot menu open on Edit imagesVariants section with several variants ticked and the three-dot menu open on Edit images

On Horizon, the assigned image is the one the gallery puts first when that variant is picked. If a swatch does not switch the photo at all, start with our guide on how to add variant images in Shopify, which covers getting a single photo to switch cleanly per colour.

Multiple variant images on Horizon

Shopify's Help Center says it plainly: each variant supports only one assigned image. That is a Shopify limit, not a Horizon one. There is no field where you attach five photos to the Black variant, on Horizon or any other theme.

Shopify's own advice is to use the product's media gallery for the extra photos. That is what the fix below does. You are not giving the variant five images. You are labelling five product images with the word Black, and hiding the ones that are not Black when Black is selected. To the shopper it looks like several images per variant, which is the part that matters.

When you actually need the code

Use the free block below if any of these is true.

  • You have more than one image per colour.
  • You keep shared images, like a size chart, that should show on every colour.
  • You want the gallery to filter, not just swap the single assigned image.

The approach has two parts. First you label every image with the colour it belongs to, using the Alt text field you already have. Then you add one Custom Liquid block, a box in the theme editor where you paste your own code, and that code reads those labels and hides the images that do not match the selected colour.

Nothing is hardcoded to your colour names. The block finds the colour option on its own by matching your option values against the Alt text, so you never type colour names into the code, and it keeps working when you add or remove images and colours later.

Step 1: tag every image with its colour

This is the label step. You are telling the theme which colour each photo belongs to, and Alt text is the field to do it in. Alt text is the short description used for accessibility and SEO, and it is editable on every image.

  • Go to Products, open your product, and click an image.
  • In the Alt text field, type the colour that image belongs to. Black, White, and so on.
  • Save the change, then do the next image.
  • Do this for every colour photo.
  • Leave shared images untagged. A size chart, or anything you want on all colours, gets no colour word.

Typing the colour name into each image's Alt text field in Shopify adminTyping the colour name into each image's Alt text field in Shopify admin

You are not changing the images. You are just naming them so the next step can tell them apart. Alt text is also good for SEO, so this is not wasted effort even beyond the gallery.

Step 2: add the Custom Liquid block

Now add the small block that does the filtering.

  • Go to Online Store, then click Edit theme on your live theme, the one at the top of the page.
  • Open the product template.
  • In the product section, click Add block and choose Custom Liquid.
  • Paste the code below and Save.

Horizon theme editor on the product template with the Add block menu open and Custom Liquid highlightedHorizon theme editor on the product template with the Add block menu open and Custom Liquid highlighted

{%- liquid
  assign vf_options = closest.product.options_with_values
-%}
<script>
(function () {
  if (window.__variantMediaFilter) return;
  window.__variantMediaFilter = true;

  var OPTIONS = [
    {%- for o in vf_options -%}
      { "values": [ {%- for v in o.values -%}{%- assign vn = v.name | default: v -%}{{ vn | json }}{%- unless forloop.last -%},{%- endunless -%}{%- endfor -%} ] }{%- unless forloop.last -%},{%- endunless -%}
    {%- endfor -%}
  ];
  if (!OPTIONS.length) return;

  var norm = function (s) { return (s || '').toLowerCase().trim(); };

  function gallerySection() {
    var g = document.querySelector('media-gallery');
    return (g && g.closest('.shopify-section')) || document.body;
  }

  function pickOption(section) {
    var alts = [].map.call(section.querySelectorAll('.product-media img'), function (i) {
      return norm(i.getAttribute('alt'));
    });
    var best = null, bestScore = 0;
    OPTIONS.forEach(function (o) {
      var score = o.values.filter(function (v) {
        var lv = norm(v);
        return lv && alts.some(function (a) { return a.indexOf(lv) > -1; });
      }).length;
      if (score > bestScore) { bestScore = score; best = o; }
    });
    return best;
  }

  function selectedValue(section, values) {
    var vals = values.map(norm);
    var r = [].filter.call(section.querySelectorAll('input:checked'), function (i) {
      return vals.indexOf(norm(i.value)) > -1;
    })[0];
    if (r) return norm(r.value);
    var s = [].filter.call(section.querySelectorAll('select'), function (el) {
      return vals.indexOf(norm(el.value)) > -1;
    })[0];
    return s ? norm(s.value) : null;
  }

  function box(m) { return m.closest('slideshow-slide') || m.closest('li') || m; }

  function apply() {
    var section = gallerySection();
    var opt = pickOption(section);
    if (!opt) return;
    var values = opt.values.map(norm);
    var selected = selectedValue(section, opt.values);
    if (!selected) return;

    var medias = section.querySelectorAll('.product-media');
    var visible = 0;
    [].forEach.call(medias, function (m) {
      var img = m.querySelector('img');
      var alt = norm(img && img.getAttribute('alt'));
      var mentions = values.filter(function (v) { return v && alt.indexOf(v) > -1; });
      var show = mentions.length === 0 || mentions.indexOf(selected) > -1;
      var el = box(m);
      el.style.display = show ? '' : 'none';
      el.hidden = !show;
      if (show) visible++;
    });
    if (!visible) {
      [].forEach.call(medias, function (m) { var el = box(m); el.style.display = ''; el.hidden = false; });
    }
  }

  function boot() {
    var section = gallerySection();
    apply();
    section.addEventListener('change', function () { setTimeout(apply, 60); });
    new MutationObserver(function (muts) {
      for (var i = 0; i < muts.length; i++) {
        if (muts[i].addedNodes && muts[i].addedNodes.length) { apply(); return; }
      }
    }).observe(section, { childList: true, subtree: true });
  }

  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
  else boot();
})();
</script>

Adding a Custom Liquid block in the Horizon theme editor and pasting the filter codeAdding a Custom Liquid block in the Horizon theme editor and pasting the filter code

One detail matters here, and it is the reason a simpler script does not work on Horizon. When a shopper changes the variant, Horizon does not just tweak the gallery. It replaces the whole gallery with a fresh block of HTML from the server. Any filter you applied to the old gallery is gone the instant the new one arrives.

The block above handles that. It watches the gallery for the new HTML and re-applies the filter every time Horizon rebuilds it. That is what the MutationObserver in the code is doing. You do not need to touch that. It just means the fix keeps holding after every colour change, which is exactly where the naive versions fall apart.

The result on a test store

With both steps in place, the gallery finally behaves. On my Horizon test store, selecting Black now shows only the Black images plus the shared size chart. The White images are gone.

Horizon gallery after the fix, Black selected showing only Black images plus the shared size chartHorizon gallery after the fix, Black selected showing only Black images plus the shared size chart

Switch to White and the gallery swaps to the White set. Same shared size chart, different colour photos.

Horizon gallery switching to White, now showing only the White imagesHorizon gallery switching to White, now showing only the White images

The behaviour matches the shorthand from the reply. Pick Black, see Black. Pick White, see White. Untagged images stay for every colour. Nothing is hardcoded, so it keeps working when you add or remove images.

Can Shopify hide variant images until a variant is selected?

Not on Horizon, with or without the block, because a Horizon product page never opens with no variant chosen. If the link has a variant number in it (the ?variant= part at the end of a product URL), that variant is picked. Otherwise Shopify picks the first variant that is available to buy, or the first variant if every one is sold out. Horizon ticks that variant's swatch before the shopper touches anything.

The block reads that ticked swatch as soon as the page loads. So the gallery opens already filtered to that colour, plus your untagged photos, and the shopper never sees the full mixed gallery. The built-in toggle behaves the same way for assigned images: the page opens with that variant's assigned image at the front and the other variants' assigned images removed.

To control which colour a page opens on, link to the product with that variant in the URL. Without a variant in the link, the first variant that is available to buy decides it.

Yes for the photos themselves. Horizon's default product layout is a grid gallery on desktop, and the Product media block's own note says the carousel is always used on mobile. The block hides grid items and carousel slides alike, so a shopper on a phone who taps Black sees the Black images and the shared ones.

The controls under a carousel are a different matter. The dots, the counter and the thumbnail strip are drawn by Horizon from the full list of images, and the block does not change them. So they can still count or show the hidden photos. If that bothers you, keep Type on Grid for desktop, and set Mobile pagination to Hint, which shows no dots on phones.

If it did not work

These are the causes the block's code and Horizon's code point to, each with the check that rules it out.

I checked the block against Horizon 4.3.0, the version Shopify released on 9 October 2026, in Shopify's public Horizon code on GitHub (updated to 4.3.0 on 13 October 2026). Everything the block relies on is still there: the media-gallery element that holds the gallery, the .product-media wrapper around each image, the slide and list item that wrap it, the swatches and dropdowns in the variant picker, and Horizon swapping in a new gallery on every colour change. If your theme is a newer Horizon release, those parts are the first place to look.

  • You edited a theme that is not live. The block only exists in the theme where you added it. Your published theme is the one at the top of the Online Store page. Click Edit theme on that one and check the block is in the product template.
  • The product uses a different template. Changes in the theme editor apply to one template. Open the product in your admin and look at the Theme template field. If it names another template, add the block to that template too.
  • An app replaces the gallery. If a gallery or variant-image app draws its own gallery, Horizon's media-gallery element and .product-media wrappers are not on the page, and the block finds nothing to hide. Turn off the app's embed (the piece an app adds to your theme, listed under App embeds in the theme editor), reload, and see whether the block works.
  • Your theme is not Horizon. The block looks for Horizon's gallery markup. On another theme it can do nothing at all. Check the theme name on the Online Store page.

Shopify Online Store page with the published theme at the top and its Edit theme button highlightedShopify Online Store page with the published theme at the top and its Edit theme button highlighted

  • Alt text typos. The block matches the colour word inside the Alt text. If the option value is Navy but a photo's Alt text says Navi, that photo will not match. Keep the spelling identical to the colour as it is written in the product's Variants section.
  • A colour name sits inside another word or colour. The match looks for the colour's letters anywhere in the Alt text, ignoring capitals. A photo tagged Light Blue also mentions Blue, so it shows on both. Red also matches inside a word like "shredded". Keep the Alt text to the colour name alone, and avoid colour names that contain each other.
  • A shared photo mentions a colour. A size chart whose Alt text says "fits black and white tees" counts as a Black and White photo and is hidden on every other colour. Leave colour words out of shared photos.
  • A photo has no Alt text. Horizon fills an empty Alt text with the product title. On my Horizon 4.3.0 test store, a size chart with blank Alt text came out as "Cotton Tee". If your product title holds a colour word, such as Black Cotton Tee, the block counts that photo as a Black photo and hides it on every other colour. Give shared photos their own Alt text, such as Size chart, or keep colour words out of the product title.
  • The colour is not a real option. The block picks the option with the most values found in your Alt text. If two options tie, it takes the one listed first on the product. If your colours are baked into product titles rather than a proper Colour option, there is nothing for it to match. Set colours up as a variant option.
  • Size letters match inside words. Size values like S, M and L are single letters, so Alt text such as "Black tee side view" also matches sizes. If that gives Size as many matches as Colour, and Size is listed before Colour on the product, the block filters by size instead. Keep the Alt text to the colour name alone.
  • A colour shows only your shared photos, or every photo. If no photo's Alt text names that colour, the block hides the other colours' photos and leaves the untagged ones. If the product has no untagged photos either, the block shows everything rather than a blank gallery. Either way, that colour has no tagged photos yet.
  • It reverted after clicking a colour. That is the re-render issue. Make sure you pasted the full block, including the part that watches the gallery, not just the filtering function.

Variant image, shared image, and swatch: three different things

Mixing these up is usually why the gallery misbehaves.

A variant image is the single assigned image Shopify swaps to when a variant is selected. One per variant.

A shared image is any other image on the product. It has no variant attached, so it shows for every option. Your extra angles and your size chart are shared images until you label and filter them.

A swatch is the little colour dot or thumbnail a shopper clicks. It is part of the variant picker, not the gallery. A swatch changing does not, on its own, filter the gallery. For the swatch side of this, see how to add variant images in Shopify.

This article is the next step up from that. Once your variant images switch, the block here makes the entire gallery filter by colour, multiple images and all, for free, on Horizon.

Frequently asked questions

Is there a free app that shows only the selected variant's images?

Yes. I make Ploqo Variant & Cover Images, a free app on the Shopify App Store that does this without alt text or code. On the product page in your admin you tick the photos for each colour, and the Horizon gallery shows only those plus the photos you keep for every colour. The setup is in the Ploqo Horizon guide.

How many images can a Shopify variant have?

One assigned image. Shopify's Help Center says each variant supports only one assigned image, and suggests using the product's media gallery for the extra photos. The alt-text tagging in this article is how the gallery knows which of those extra photos belong to which colour.

Does the block change my products or images?

No. It only hides photos on the product page while a shopper views it. The one change to your product data is the alt text you type in Step 1. Delete the block and the full gallery comes back.

Does this need Shopify Plus or a paid app?

No. Horizon is a free theme made by Shopify, and the Custom Liquid block and the Alt text field are part of the theme editor and the product page.

Rather not keep alt text and Liquid in sync?

The fix above depends on alt text and a Custom Liquid block. This free app does the same job from the product page in your admin: tick the photos for each colour, and the gallery shows only those, plus shared photos like a size chart. The setup is in the Horizon guide.

Get Ploqo on the Shopify App Store

Answered on the Shopify Community

A merchant ran into this and asked about it on the forum. I worked through it on a test store and posted the fix there on August 2, 2026. You can read the original thread, including the follow-up questions, over on the Shopify Community.

View the original thread