Product context

Render product details, variant selection, availability, and quantity controls from resolved storefront data.

On a product page, ctx.product contains the route-resolved product and its variants. Prices, availability, purchase state, and quantity limits already reflect the active storefront, market, inventory policy, and the merchant’s variant → product → store settings.

Quantity controls#

Use quantity_max as the max attribute on a fresh add-to-cart input. It is the largest quantity accepted right now after combining stock, remaining backorder capacity, and max_order_quantity. A null quantity_max means there is no finite runtime bound. A value of 0 means the product or variant cannot currently be added.

max_order_quantity is the resolved merchant policy: variant first, then product, then the store default. It may be null even when quantity_max is finite because stock can still provide the active limit.

html
{% assign purchasable = product %}
{% if product.selected_variant %}{% assign purchasable = product.selected_variant %}{% endif %}
{% form "cart_add" %}
  <input type="hidden" name="product_id" value="{{ product.id }}">
  {% if product.selected_variant %}
    <input type="hidden" name="variant_id" value="{{ product.selected_variant.id }}">
  {% endif %}
  <input type="number" name="quantity" min="1" value="1"{% if purchasable.quantity_max %} max="{{ purchasable.quantity_max }}"{% endif %}>
  <button type="submit"{% unless purchasable.available_for_sale %} disabled{% endunless %}>Add to cart</button>
{% endform %}

Product and variant fields#

  • product.max_order_quantity and product.quantity_max apply directly to simple products.
  • product.variants[*].max_order_quantity and quantity_max carry each variant’s resolved limits.
  • product.selected_variant exposes the completed shopper selection; product.display_variant drives the current display while selection is incomplete.
  • available_for_sale and purchase_state remain the authoritative controls for whether the item can be submitted.