Shopify 2.0 Dawn - How to hide unavailable variants?

Topic summary

Core Issue: Users seek to hide unavailable variant combinations in Shopify’s Dawn 2.0 theme, which has different code structure than older themes like Debut.

Key Distinction: Two types of unavailability exist:

  • Sold-out variants: Items temporarily out of stock (should be greyed out/faded)
  • Does-not-exist combinations: Invalid variant pairings that were never created (should be hidden entirely)

Technical Challenges:

  • Dawn’s JavaScript differs significantly from legacy themes, making old solutions incompatible
  • Multi-variant products (e.g., color + size) require hierarchical logic to avoid hiding all options when only some combinations are unavailable
  • Dropdown selectors can’t be styled via CSS, only hidden; pills/buttons offer better visual feedback

Solutions Discussed:

  • Free code snippets: Community members share GitHub solutions, though compatibility varies across Dawn versions. JonoNZ provides a GitHub repository with version-specific branches (Dawn 15 required rewrite)
  • Paid options: Apps like Camouflage ($7/month for 2-3 variants) and custom code snippets that differentiate between sold-out and non-existent variants
  • Implementation: Requires modifying global.js and variant selector templates; non-technical users may need Shopify Expert assistance

Current Status: Discussion remains active with users troubleshooting implementation across different Dawn versions.

Summarized with AI on November 5. AI used: claude-sonnet-4-5-20250929.

Hi there,

The Dawn theme is new, so previous answers/code are completely different (or look to be). My css is decent but my javascript is lame, I’m a designer sorry.

  1. Does anyone know how to hide unavailable variants from the selects in Shopify 2.0 Dawn?

  2. What’s the best way to add custom text as the first option in the selects? e.g. ‘Choose a size…’ and ‘Choose a color…’ etc. Should I hard-code, or pull the option name using Liquid, or use the JS for this as well?

Here’s an older example of how to hide unavailable variants in the older Debut theme: https://www.youtube.com/watch?v=vspWDu_POYA

Here’s a link to the gist referenced in that video: https://gist.github.com/jonathanmoore/c0e0e503aa732bf1c05b7a7be4230c61

Here’s the new code from Dawn at line 497 in /assets/global.js

Any help or pointers in the right direction would be much appreciated. Cheers

class VariantSelects extends HTMLElement {
      constructor() {
        super();
        this.addEventListener('change', this.onVariantChange);
      }
    
      onVariantChange() {
        this.updateOptions();
        this.updateMasterId();
        this.toggleAddButton(true, '', false);
        this.updatePickupAvailability();
    
        if (!this.currentVariant) {
          this.toggleAddButton(true, '', true);
          this.setUnavailable();
        } else {
          this.updateMedia();
          this.updateURL();
          this.updateVariantInput();
          this.renderProductInfo();
        }
      }
    
      updateOptions() {
        this.options = Array.from(this.querySelectorAll('select'), (select) => select.value);
      }
    
      updateMasterId() {
        this.currentVariant = this.getVariantData().find((variant) => {
          return !variant.options.map((option, index) => {
            return this.options[index] === option;
          }).includes(false);
        });
      }
    
      updateMedia() {
        if (!this.currentVariant || !this.currentVariant?.featured_media) return;
        const newMedia = document.querySelector(
          `[data-media-id="${this.dataset.section}-${this.currentVariant.featured_media.id}"]`
        );
        if (!newMedia) return;
        const parent = newMedia.parentElement;
        parent.prepend(newMedia);
        window.setTimeout(() => { parent.scroll(0, 0) });
      }
    
      updateURL() {
        if (!this.currentVariant) return;
        window.history.replaceState({ }, '', `${this.dataset.url}?variant=${this.currentVariant.id}`);
      }
    
      updateVariantInput() {
        const productForms = document.querySelectorAll(`#product-form-${this.dataset.section}, #product-form-installment`);
        productForms.forEach((productForm) => {
          const input = productForm.querySelector('input[name="id"]');
          input.value = this.currentVariant.id;
          input.dispatchEvent(new Event('change', { bubbles: true }));
        });
      }
    
      updatePickupAvailability() {
        const pickUpAvailability = document.querySelector('pickup-availability');
        if (!pickUpAvailability) return;
    
        if (this.currentVariant?.available) {
          pickUpAvailability.fetchAvailability(this.currentVariant.id);
        } else {
          pickUpAvailability.removeAttribute('available');
          pickUpAvailability.innerHTML = '';
        }
      }
    
      renderProductInfo() {
        fetch(`${this.dataset.url}?variant=${this.currentVariant.id}&section_id=${this.dataset.section}`)
          .then((response) => response.text())
          .then((responseText) => {
            const id = `price-${this.dataset.section}`;
            const html = new DOMParser().parseFromString(responseText, 'text/html')
            const destination = document.getElementById(id);
            const source = html.getElementById(id);
    
            if (source && destination) destination.innerHTML = source.innerHTML;
    
            document.getElementById(`price-${this.dataset.section}`)?.classList.remove('visibility-hidden');
            this.toggleAddButton(!this.currentVariant.available, window.variantStrings.soldOut);
          });
      }
    
      toggleAddButton(disable = true, text, modifyClass = true) {
        const addButton = document.getElementById(`product-form-${this.dataset.section}`)?.querySelector('[name="add"]');
    
        if (!addButton) return;
    
        if (disable) {
          addButton.setAttribute('disabled', true);
          if (text) addButton.textContent = text;
        } else {
          addButton.removeAttribute('disabled');
          addButton.textContent = window.variantStrings.addToCart;
        }
    
        if (!modifyClass) return;
      }
    
      setUnavailable() {
        const addButton = document.getElementById(`product-form-${this.dataset.section}`)?.querySelector('[name="add"]');
        if (!addButton) return;
        addButton.textContent = window.variantStrings.unavailable;
        document.getElementById(`price-${this.dataset.section}`)?.classList.add('visibility-hidden');
      }
    
      getVariantData() {
        this.variantData = this.variantData || JSON.parse(this.querySelector('[type="application/json"]').textContent);
        return this.variantData;
      }
    }
    
    customElements.define('variant-selects', VariantSelects);
    
    class VariantRadios extends VariantSelects {
      constructor() {
        super();
      }
    
      updateOptions() {
        const fieldsets = Array.from(this.querySelectorAll('fieldset'));
        this.options = fieldsets.map((fieldset) => {
          return Array.from(fieldset.querySelectorAll('input')).find((radio) => radio.checked).value;
        });
      }
    }
    
    customElements.define('variant-radios', VariantRadios);
3 Likes

Bump

Thats a little tricky. Are you only using one variant? The issue of hiding things is when you have different sizes and such. Say you have TShirts and you offer them with a color option and a size option. Your green tshirt is available in Small, Medium and Large, but it’s out of stock on XL. Well you can’t hide XL because your XL is available in Red. You can’t hide Green because you have it available in small medum and large.

2 Likes

Thanks for the reply,

I think that’s why this has to be handled in JS - so it’s evaluated and updated each time the customer makes a selection.

Hense all the previous hacks used javascript.

However, it’s time for an official Shopify way of handling this, especially in the flagship 2.0 Dawn theme - no?

3 Likes

I disagree, but only because I think there’s a reason they haven’t done it and it’s kind of from a usability standpoint. Given the last example, let’s say you land on the page on your XL Red T-Shirt variant through way of a link. The green option would be hidden, because you don’t have green XL T-Shirts Available. You might not even know there’s a green option in that case. Or what if you land on the page through a link and the variant is already unavailable? You’d be in the same boat you’re in now, it would show sold out and you wouldnt see any options to chose from. It makes more sense to show all variants and let the user discover that one or more is out of stock than to limit what they’re seeing based on stock. Because when do you hide what? You have to do it based on the users interaction. What if there’s 3 colors and 3 sizes and one color is out of stock for every size? Then you just don’t see anything to choose from. This problem gets multiplied over however many variant options you have.

Edit: I should note, I think this WOULD make sense if you only have one variant option, such as size. Even in that case though, then they may think you don’t offer that size at all for that item.

1 Like

I’m not suggesting doing this on page load. If it’s not user-initiated, then don’t run the script.

Couldn’t agree more. In our experience, users will almost always interact with the first select, first.

  • So when elements change based on interactions, you instantly learn how it works
  • But when nothing changes, customers don’t discover or learn anything
  • That’s why customers fail to understand that it’s the state of the selects, which make combinations unavailable
  • Therefore, customers don’t know how to fix ‘Unavailable’ - and why would they?

We get questions like ‘When will you get more pillowcases?’

Well, we have them in stock right now but because of the state of the selects, it looks like Pillowcases are unavailable when they’re not.

This is pointless right?

And for every person that bothers to ask, 100 assume we’re out of stock and leave.

Additionally, for our shop, people with money are much more likely to be older, so are less likely to understand how this works without visual changes based on interaction.

I totally agree that sold-out items should be greyed and not hidden. However, ‘not possible’ is a different exception that’s not currently handled well from the customer’s point of view - right?

How it works currently already creates situations where customers think that ‘Unavailable’ means ‘Sold out’. This is what we’re trying to fix.

Because it’s complex from a developer/logic point of view, it’s probably considered advanced - so palm it off onto advanced theme customisation or worse, an app (which don’t work with Shopify 2.0 right now anyway).

But from a design or UX point of view…

  1. This isn’t advanced
  2. It’s as basic as choosing what you want
  3. Isn’t this the whole point of e-commerce?

If that requires better logic in the variant section of the product page, then that’s what it requires. It’s time to get this sorted - right?

Especially in Dawn. At least show us how to fade sold-out and hide ‘not possible’ in JS and let us worry about the implications.

We’ll have a good idea of what works based on customer questions and ye old favourite, testing and measuring. Ya know?

I guess I’m a little confused because the title of your topic is how to “hide” unavailable variants. Also you said you don’t want it to run on page load, but it would have to say if your default variant was sold out. Greyed out is a little different. Ill make a similar product based off what you posted here and see if I can’t come up with something.

1 Like

Thanks for the reply, much appreciated…

Yes we want to hide unavailable but fade sold-out. The two aren’t the same and are handled differently by Shopify.


SOLD OUT

Sold-out is obviously based on stock and the buy button switches to SOLD-OUT. This is easily understood by customers so we simply want to fade SOLD-OUT variants.


UNAVAILABLE

Unavailable is different and occurs when a combination of selectors results in a product that’s ‘not possible’. Shopify changes the buy now button to UNAVAILABLE but people think this means SOLD-OUT like you just thought - that’s why it’s confusing.


This video explains it well - you can’t have a Samsung iPhone but because of the way default variants work in Shopify, a customer can select a Samsung iPhone: https://youtu.be/vspWDu_POYA?t=9

And that video also shows how to hide Unavailable combinations in Debut but the JS in Dawn is totally different.

Hope that makes more sense and thanks for taking a look, much appreciated.

Cheers

Ben

1 Like

Git issue raised in Dawn: https://github.com/Shopify/dawn/issues/459#issue-975818428

I wish there was a way to raise issues with designers at Shopify. Showing shoppers products that don’t exist is a weird outcome - whatever the reason (which clearly isn’t shopper focused).

1 Like

I have a similar issue. I am using the Dawn theme and I would like to hide product that have only one variant. I look in the code and I see that:

So I tried to name my option and value “default” as I did when I was using the Minimal theme but it doesn’t work.

Thank you so much for your help!

There’s a git issue open but showing shoppers variant combinations that don’t exist is really a design/UX issue so it’ll probably get ignored or closed by developers: https://github.com/Shopify/dawn/issues/459

2 Likes

Hello @Ninthony , I only have one variant is there any solution?

Thank you in advance

Hi All,
I found similar gig

Suggestion: add an option to this plugin to differentiate between “sold out” and “unavailable” (invalid option combination dots not exist) variants. Many people want to hide invalid but NOT out of stock variants.

Also, your plugin is showing as out of stock and not purchasable. Is this a theme code snippet for sale, or an app?

1 Like

Looks promising, I’ve bookmarked your page to keep an eye out for when you’ve added some more details. A code snippet is what’s desired, along with a solution using vanilla JavaScript (no jquery) to basically replicate the old linked-options tweak that would remove unavailable options. If you can get this developed to work with Dawn you’ll have a winner, especially pill variant selectors since the original solutions only worked with drop-downs. I encourage you to read through all the comments on the Dawn issue to get a feeling what people are after including a few partial solutions that might provide some examples or tricks. The out-of-stock vs unavailable are two separate issues, and the unavailable problem is the one that will get a lot of attention if you solve it without slowing Dawn down with things like jquery. I’d urge you to chime in on that GitHub issue if you successfully address the concern there.

2 Likes

THOUGHTS

Sold-out VS does-not-exist
@Ben31 has an important point. There are 2 types of unavailable variants. Sold-out variants and does-not-exist combinations. I recommend hiding does-not-exist and greying out sold-out variants to solve the issues mentioned by @Ninthony

How many variants?

If there’s one variant the it’s simple. We’ll hide the unavailable ones.

If there are 2+ variant levels (e.g color and size) we need a hierarchy. First level (color) is only greyed out / hidden if all sizes for that color are unavailable. If blue does not have any sizes, we can grey out blue.

Otherwise we will show the first level (color) and available sizes for chosen color like this

image.gif

Greying out
Pills can be greyed out. Dropdown variants can’t. Pills require less clicks and show availability without clicking. I recommend using pills.

I suggest reducing opacity instead of editing background color like

.sold-out{
  opacity:0.3 !important;
}

Dropdowns
Dropdowns are harder than pills because unavailable variants can’t be “greyed out” or styled using CSS. Dropdown items can be hidden completely but not styled.

I recommend hiding does-not-exist combinations and adding a text after for sold out ones like this

You could disable sold-out dropdown items to make them look “greyed out”. Disabled out-of-stock variant can’t be clicked. If you have an app like Back In Stock which will notify the customer when a variant is back you’ll want customer to be able to click on a sold out one and be notified. If you’re not using back in stock or similar, you can hide does-not-exist ones and disable (grey out) out of stock variants like this

FREE OPTIONS

I shared a free snippet @King-Kang . It will work for Dawn using single variant. The code is too long to add here so here’s a link to a gist in Github.

Other good free options are hard to find. There are tons of code snippets in these forums, blog posts and stackoverflow.com but as themes develop, they’re often outdated and it’s not possible to get support. For non technical users it’s ususally not possible to fix them or edit them to work for another theme.

This tutorial on Shopfify Forums is perhaps the best starting point for editing or hiring a Shopify Expert to implement it. Googling will find more free tutorials like this one.

I wasn’t able to make any of them work however.

PAID OPTIONS

I sell my own code snippet which does this all. Hide, grey out, strikethrough. Options for pills and dropdowns, multiple variants. Different styles for does-not-exist combinations and sold-out. One time payment. It supports Dawn and many other themes.

Camouflage seems like one of the best Shopify Apps. It works in the front end which is good as it allows flexibility for custom CSS. This does not differentiate between does-not-exist and sold-out which I think is imporant. Currently free for 1 variant, $7/month 2-3 variants.

Autohide Plus is another app. It seems to work in the backend so it will not have as much flexibility in terms of designs. No greying out or strikethrough. Just hide. Also does not seem to differentiate between sold-out and does-not-exist. No free plan currently.

Feel free to dm me if my answer was helpful and you’d like more info 1-on-1. I love solving Shopify variant problems :smiling_face:

2 Likes

@fenixk I can’t really tell if your plugin is only hiding/modifying the appearance of valid/sold-out variants or is ALSO handling the separate issue of nonexistent/invalid option combinations, which is what the linked-options tweak you referenced does for vintage themes. There are many solutions for 2.0 themes to indicate a variant is sold out, but as of yet no solutions to hide/indicate invalid selections. That GitHub issue sums it up exhaustively. The first person to come up with a pure-js solution to the “unavailable” problem will sell a LOT of snippets and I’ll be first in line!

1 Like

@amanda-91 My code snippet also handles nonexistent/invalid option combinations with complete freedom to only hide/grey out invalid or out-of-stock. Or both. Or hide invalid and grey-out sold-out.

I believe both apps I mentioned, Camouflage and Autohide Plus also do that to some extent but not 100%. They also can hide invalid combinations. But those apps do not currently make a distinction between sold-out and invalid. My testings seems to indicate these 2 apps require always hiding both, sold-out and invalid. So they might not be ideal if it’s important for you to show sold-out variants BUT hide invalid variants.

Hi @fenixk ,
may I know plugin price please? I’m interested to implement
also can you please share any reference site where this installed or your demo store link?
I would like to check it first and then we can proceed
Thanks,
Gef

I don’t want to flood this forum too much with just my product. I’ll try and provide more general information and multiple possible solutions, along with their pros and cons.

For info on my plugin / code snippet, you can go here.
It has details, FAQ’s and contact details for more info. I’ll add a demo store link as well.

Feel free to DM me with any questions. I love solving this issue, whatever the method :slightly_smiling_face:

1 Like