I found this one in a Shopify Community thread that collected 13 posts in 24 hours and still has no accepted answer. A merchant on the Horizon theme asked the question store owners have asked for a decade: when a shopper picks Black, show only the black images — no paid app, no Plus.
The thread is a museum of every classic wrong answer: a layout setting sold as filtering, the one-image-per-variant confusion, a "send me your store URL" service pitch, and a working code snippet the OP couldn't get running. I've watched this question get half-answered for years, so here's the whole picture — including why the "correct" code so often "doesn't work."
Root cause: two things that look alike
Shopify's data model gives you two different things:
-
A variant can carry its own media —
variant.featured_image/variant.featured_mediain Liquid,ProductVariant.mediain the Admin GraphQL API. This is what you set when you assign an image to a variant in the admin. Exactly one is "featured," and themes (Horizon included) swap it into the main gallery slot on selection. Native, free, every plan. -
The product's media set —
product.media— is a flat pool shared by all variants. Any image not assigned to a variant belongs to every color simultaneously. There is no native structure for "these five images belong to Black."
So "show only the selected variant's images" is two different problems:
| Case | What you want | Native support |
|---|---|---|
| A | One representative image per color, swapped on selection | Yes — variant featured image, every theme |
| B | A gallery per color (3–8 shots each), filtered on selection | No — not in the data model, not a Horizon setting |
If you're in Case A, stop here: assign each variant's featured image in Products → your product → Variants. On Horizon, additionally enable "Hide other variants' media after selecting a variant" in the Media Gallery block settings (field report, community-verified by three independent posters in topic 659928 — it hides down to the one assigned image per variant, not a multi-image set).
Everything below is Case B.
Minimal reproduction
Five minutes on a dev store:
- Create a product "Test Tee", option Color:
Black,White. - Upload 6 images: 3 black, 3 white. Assign the first black image as Black's featured image, first white as White's.
- Publish with Horizon, Media Gallery in grid mode (the default).
- Select Black on the storefront: the main image swaps — and the other 5 images, including all 3 white shots, stay in the gallery. Select White: same in reverse.
That's the ceiling of native behavior. No toggle changes it.
Route 1 — Alt-text tagging + gallery filter (free, code, no app)
Tag every color image with its color in Alt text (Products → product → click image → Alt text → Black, White, …; leave shared images like size charts untagged). Then filter the gallery on the selected option value, in a Custom Liquid block or section on the product template:
{% assign current_variant = product.selected_or_first_available_variant %}
{% assign selected_color = current_variant.options.first %}
{% for media in product.media %}
{% if media.media_type == 'image' %}
{% if media.alt == blank or media.alt == selected_color %}
<img
src="{{ media | image_url: width: 800 }}"
alt="{{ media.alt | escape }}"
loading="lazy">
{% endif %}
{% endif %}
{% endfor %}
The notes that make or break this in production:
-
product.mediafiltered withwhere: 'media_type', 'image'is the documented pattern;media.altis the string you typed in the admin. Both documented. -
Alt text must match the option value exactly —
Black≠black≠Black(trailing space). This, plus browser cache, is why the OP reported the community code "not working." - The snippet filters on first render only. Switching colors is a client-side event — you need a small JS listener on the variant picker that re-filters (or hides/shows) gallery items without a reload. This is the half people paste-and-pray without.
- Untagged images stay visible for every color — exactly what you want for size charts and lifestyle shots.
- This approach was tested on a live Horizon store (grid layout) with before/after screenshots in the thread; the untagged size chart correctly persisted across colors.
Route 2 — Shopify Combined Listings (free, first-party, Plus only)
If each color deserves its own full media set — and its own URL for ads and SEO — the first-party answer is Combined Listings: each color is a separate product with its own images, and the combined listing displays all child products on one product page. Zero code. The catch is hard: Combined Listings are available only to stores on a Shopify Plus plan (shopify.dev, verified 2026-08-05). For the OP, who excluded both apps and Plus, this route is out — but it's the correct answer for Plus stores, and worth knowing before you write any Liquid.
Route 3 — Apps
Exist, work, out of scope: the constraint was "no paid app," and Routes 1–2 cover the free space completely.
Decision tree
One image per color? → Variant featured image (+ Horizon's
"hide other variants' media" toggle). Done.
Multiple images per color?
├─ On Plus? → Combined Listings. No code.
└─ Not on Plus? → Alt-text tagging + Custom Liquid/JS filter.
Match alt text to option names exactly.
Checklist
- Decide your case first: one image per color (native) vs. a gallery per color (code or Plus).
- Case A: assign each variant's featured image; on Horizon, enable "Hide other variants' media" in the Media Gallery block.
- Case B, Route 1: tag every color image's Alt text with the exact option value (case, spelling, trailing spaces).
- Filter
product.mediabymedia_type == 'image'andmedia.alt == selected_color; leavemedia.alt == blankitems visible for shared shots. - Add the JS listener on variant change — server-rendered Liquid only filters the first paint.
- Test on grid and carousel; the layout setting changes markup, not filtering.
- Hard-refresh / incognito before concluding "the code doesn't work" — stale cached HTML is the #1 false negative.
- On Plus? Skip all of it: Combined Listings gives each color its own product and media set, natively.
Community thread content (the Horizon "Hide other variants' media" setting, the tested alt-text solution, the OP's failed implementation) is a field report from Shopify Community topic 659928; every load-bearing technical claim is verified against Shopify's official documentation (Liquid variant.featured_image/featured_media, media.alt, product.media where-filter, Admin GraphQL ProductVariant.media, Combined Listings) as of 2026-08-05.
Originally published at https://clawmama.run/blog/shopify-horizon-variant-media-filter/
Top comments (0)