“Thank you! I use the Horizon theme. Could you please adapt the snippet specifically for Horizon? The event name and quantity selector may be different from other themes.”
{%- comment -%} Limit the quantity to the selected variant's stock {%- endcomment -%}
<script>
(function () {
var STOCK = {
{%- assign first = true -%}
{%- for v in product.variants -%}
{%- if v.inventory_management != blank and v.inventory_policy != 'continue' and v.inventory_quantity > 0 -%}
{%- assign cap = v.inventory_quantity -%}
{%- if v.quantity_rule.max != blank and v.quantity_rule.max < cap -%}{%- assign cap = v.quantity_rule.max -%}{%- endif -%}
{%- unless first -%},{%- endunless -%}"{{ v.id }}": {{ cap }}{%- assign first = false -%}
{%- endif -%}
{%- endfor -%}
};
function variantId() {
var el = document.querySelector('product-form-component input[name="id"], form[action*="/cart/add"] input[name="id"], input[name="id"]');
return el ? el.value : null;
}
function apply() {
var id = variantId();
document.querySelectorAll('quantity-selector-component').forEach(function (qs) {
var input = qs.querySelector('input[name="quantity"]');
if (!input) return;
var min = input.getAttribute('min') || '1';
var step = input.getAttribute('step') || '1';
var cap = STOCK.hasOwnProperty(id) ? String(STOCK[id]) : null;
if (typeof qs.updateConstraints === 'function') qs.updateConstraints(min, cap, step);
else if (cap) { input.setAttribute('max', cap); if (parseInt(input.value, 10) > +cap) input.value = cap; }
else input.removeAttribute('max');
});
}
document.addEventListener('shopify:product:select', function (e) {
if (e && e.promise && e.promise.then) e.promise.then(apply, apply);
setTimeout(apply, 350);
});
if (document.readyState !== 'loading') apply();
else document.addEventListener('DOMContentLoaded', apply);
})();
</script>
The quantity now stops at that variant’s stock, the plus button greys out at the limit, and it re-caps every time the shopper changes variant.
Note
The block sits in the product template, so it covers every product on that template.
Sold-out variants are already blocked by the Add to cart button, so those are left alone.
If a variant allows overselling, it stays unlimited on purpose.
Limitations:
Note: the “up to 5 in stock” (for example) limit is fixed when the page loads. If someone else buys some of that variant meanwhile, your page still lets you pick up to 5 until you refresh. Shopify catches it at checkout, so you can’t oversell, but the on-page number can be stale until then.
“Thank you! I use the Horizon theme. Could you please adapt the snippet specifically for Horizon? The event name and quantity selector may be different from other themes.”
Thank a lot, good solution with liquid bloc in product not in general code, easy to do.