Shopify themes, liquid, logos, and UX
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.
Does anyone know how to hide unavailable variants from the selects in Shopify 2.0 Dawn?
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}§ion_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);
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.
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?
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.
@Ninthony wrote:"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?"
I'm not suggesting doing this on page load. If it's not user-initiated, then don't run the script.
@Ninthony wrote:"...let the user discover"
Couldn't agree more. In our experience, users will almost always interact with the first select, first.
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.
@Ninthony wrote:"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."
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?
@Ninthony wrote:"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."
How it works currently already creates situations where customers think that 'Unavailable' means 'Sold out'. This is what we're trying to fix.
@Ninthony wrote:"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."
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...
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.
Thanks for the reply, much appreciated...
@Ninthony wrote: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.
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
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).
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
We've discovered that many users don't understand this. If they land on the page and the "small" variant is sold out, often times they are lazy and think the whole thing is sold out. That is why this feature is so important. We lose sales on a daily basis from this and the only way to fix it is to delete the variant -- and then lose all of the data attached it, as well as have to recreate it if we restock. When we delete sold out variants, we make more money -- but we lose out on our data analytics. I have yet to find a fix for this.
I see. What would be the ideal solution for you? I'm doing my best to solve this specific issue (and have done it for about 8 Shopify stores)
Would you like to hide or grey-out the sold out variants? You can check my previous reply. It has 3 ways to achieve that.
OP here, thanks for helping us - much appreciated.
The best solution is to hide variant combinations that don’t exist (I mean, why show people products that don’t exist?), then grey sold-out variants and change the button to ‘Sold-Out’. That way it’s super clear when something is normally available but is just sold-out.
It still baffles me that Shopify doesn’t properly handle exceptions and thinks this is all Ok - it’s not.
Thanks. Agreed. Fully hiding the variants that do not exist (if there is no plan on having them in stock ever). And then greying out the sold out variants is the best user experience.
I also feel that for some stores it might be better to add a little "Sold" label to the variants that are sold out. Example:
If everything is greyscale, then the white buttons + selected dark variant, + the greyer out variants might just become black&white blur. Something more distinctive (like screenshot) could be a more clear user experience. But it depends.
FYI I just updated my little code snippet which I'm developing to solve this problem. It now supports 3 levels of variants and can do what you requested. Grey out the sold-out variants and fully hide non-existing variants.
Thanks @fenixk, OP here. Your continued work on this is much appreciated!
Just so we're clear on unavailable variants, it's that they can never exist. e.g. See example on the left below...
Currently, visitors can choose a case for an Apple Galaxy S21. However, an Apple Galaxy S21 will never exist. But worse, variants often load alphabetically, which means product pages often load showing a product that will never exist?
And for a variety of reasons, many visitors don't notice that it's the selects which are configured incorrectly, and so assume 'Unavailable' means sold-out, and move on.
I'm sure you understand this but many don't so just wanted to clarify so we're on the same page.
Your example works great for short variant names but not so good for long variant names or lots of variants. If we had a choice, we'd prefer something like the example below...
Also, it would be good if options could be configured via Shopify's new blocks system...
Depending on variant name length, the Pill system in your screenshot might not work - it wouldn't work for our catalogue for example. So to make it compatible with as many merchants as possible, having the selects options as shown would tailer your app to almost all catalogues.
The above is a wish-list and you're obviously free to develop your app any way you'd like so this is just an ideal. Personally, I don't think this is all so advanced that merchants should use an app in 2022 but I'm super grateful you've shown an interest in helping solve this for us.
I hope that makes sense. Cheers, Ben.
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:
<div class="product-form__input{% if product.has_only_default_variant %} hidden{% endif %}">
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!
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?
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.
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
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 ☺️
@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!
@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 🙂
Hi Fenix,
cold you please tell me where I should add it?
.sold-out{
opacity:0.3 !important;
}
tnks
@fenixk Thanks for mentioning the Camouflage app. Yes, it does differentiate between sold out and unavailable variants 😉
If anyone is still looking for a way to hide unavailable options (but leave Sold Out variants alone), here's my solution:
https://github.com/JonoHall/Dawn-Enhanced
@JonoNZ not sure what I'm doing wrong. I cant get this working by just making the two changes and then the changes to lines 37-40 in the JS. Anything else I need to do? Do i need to install the whole Dawn-Enhanced theme for just this change? Sorry, I'm a bit of a noob.
Can you post screenshots of your changes? And a link to your site if possible?
Do you know how to make this work with Prestige? This is exactly something i need.
DUDE! That's amazing! Thank you so much for this. Took some time to find it and that screenshot definitely was very helpful. Amazing.
Hi,
thanks for your help. In Dawn 15, non-existent variants are still displayed. Has there been an update? Thanks!
I'm not sure, but wouldn't the following custom CSS code work?
.product-form__input--pill input[type="radio"]:disabled + label,
.product-form__input--pill input[type="radio"].disabled + label {
display: none;
}
Hi Basti,
I think I've cracked it for v15, just testing it at the moment. I'll post an update in the coming days.
Hey Basti, V15 changed a few things and so I've rewritten how the hack works. Check out the new branch below, let me know if you have any probs:
https://github.com/JonoHall/Shopify-Hide-Unavailable-Options/tree/Dawn-15
Hi Jono,
looks good to me!! Thank you very much!
Tried the dawn 15 version myself, and it seems to consistently get stuck in some kind of infinite loop on listings with multiple variation options if I change the top heading.
For instance, if I have Color as the primary heading, and Size as the secondary one, it will correctly work at hiding nonexistent variants on whatever the default color is that the page loads with.
However, if I click to select a new color, it locks up. I tried adding a console message to track what was looping since the observer seemed like the most likely culprit
Apologies for awful whitespace mangling from the message box
When it freezes, the console spits out an infinite number of mutationRecords. Once it's in the infinite loop 'mutationsChecked' ends up being the same value each time (31), and the data in the mutationRecord appears to be the same each time, so it appears to be stuck on one record in particular.
EDIT: Commenting out this line
//if a new option has been selected, restart the whole process
//if(change) variantSelects.dispatchEvent(new Event('change', { bubbles: true }));
seems to fix things.
Hopefully this feedback is helpful, I really appreciate you making this script 🙂
Yeah, that's the new bit of script I've had to add. Basically the new version of Dawn deletes and rebuilds the variant list, deleting my code every time.
I don't have any issues on my live site, but I've seen the loop issue before on one of my test websites. Are you by any chance using 3 levels of variants?
Just 2 levels of variant, but the subvariants under the top level variants don't overlap at all (ie: Variant A has sizes 1,2,3, Variant B has 4,5,6, Variant C has 7,8,9), which might be relevant?
Hi team,
If you're wondering about the lack of updates to my hack; Unfortunately, after 10 years of Shopifying, the company I work for has made the ill-fated decision to move away from Shopify. Which means I no longer have an active interest in the platform.
I created this hack with zero prior knowledge of Javascript. I made it open source as I was actually hoping someone with a bit of a background would have used my code as a proof of concept and made a more robust version. But alas, no one has suggested any changes or fixes.
So, my code will remain unstable at this point (some people have found success, some have come across the loop issue, I've seen both and I'm not sure how to fix it).
For anyone wanting to know why it's broken in the new version, it's because Dawn now removes the entire selector block on each change which in turn removes the change detectors I had on each selector. So, each time the entire block is removed and re-added, I had to add a new mutation observer in (which is probably causing the infinite loop issue).
I'll be back to Shopify one day, hopefully by then someone will release a better version. Because, as it seems, this is a fundamental issue that Shopify is not going to resolve themselves.
Until then, I'm not sure what you can do to resolve this, but in any case, good luck and happy eCommercing!
Just googled "hide unavailable variants" and found the following video. Just in case some is still looking for a solution
That idiot just copied my code and posted it up as his own for profit. Please remove the link to his page, as it just gives him more SEO.
I asked him to add my Github as a source and he ignored me.
His code won't work for the latest version of Dawn, and I suspect he's waiting for me to patch it lol.
Have you patched it for the new Dawn? I just tried your Github code and had the same issue as Reference. Hoping for a fix!
Hello JonoNZ,
Thanks for your code, I have updated it and made it compatible with the latest version of Dawn. Superb Man
Hello Monsur_riaz,
It's excellent you managed to get it updated successfully. Would you mind to share the updated code, please? I have been struggling with this for quite some time, and JonoNZ's code seems to be the only viable solution. Thanks
Hi Harry,
Make sure you're trying the unreleased Dawn 15 branch:
https://github.com/JonoHall/Shopify-Hide-Unavailable-Options/tree/Dawn-15
Hi Jono,
Thanks for getting back to me.
Yes, confirmed I am using unreleased Dawn 15 branch, from the link you included. It seems to work correctly up to a point, and after clicking around the variations a few times, it starts to lag and then locks the whole page up. This is happening where there a 3 variations.
I did a Pull Request with a fix about an hour or two ago to hopefully fix that. Did you try it with that tweak? It’s the latest version of the 15 branch.
Thank you.
Is it this one: https://github.com/JonoHall/Shopify-Hide-Unavailable-Options/commit/924666719353f19bdb527555448d0139...
on line 58?
If so, yes I tired it, and the same still persists
We want to take a moment to celebrate the incredible ways you all engage with the Shopi...
By JasonH Oct 15, 2024Starting a B2B store is a big undertaking that requires careful planning and execution. W...
By JasonH Sep 23, 2024By investing 30 minutes of your time, you can unlock the potential for increased sales,...
By Jacqui Sep 11, 2024