Adding multiple variants to cart with their own quantities for our wholesale site

Topic summary

A developer is building a custom wholesale product page that allows distributors to add multiple variants with individual quantities to the cart simultaneously, avoiding third-party apps to reduce loading time.

Current Challenge:
The variant picker pills are functioning for display purposes, but the add-to-cart functionality isn’t properly capturing individual variant IDs and quantities. Instead, all quantity inputs reference only the selected variant from the form.

Technical Progress:

  • Successfully extracted variant IDs using a standard for loop
  • Encountering issues where quantity selectors aren’t being honored
  • Cart popup not triggering correctly
  • Lost price display in latest iteration

Desired Functionality:
Either separate add-to-cart buttons per variant row, or a single button that reads all variant quantities and adds them collectively. The developer wants to maintain the existing variant pills for viewing details while decoupling them from the cart/quantity controls.

Status: Ongoing troubleshooting of Liquid template code for the variant picker component. No resolution yet.

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

Good day to everyone.

I’m looking to allow our distro customers to add multiples of each variant to the cart to make the process fast and convenient.

Now I’m stuck on getting the variant ID of each variant, instead it’s just presenting the selected variant in the form to everything.

I’d like to keep the pills for the customers to click and see the details of the specific variant, but have the add to cart and quantity use the variant next to it effectively separating the pills from the cart button and quantities.

Alternatively 1 add to cart button that reads all of the variant and quantities and adds them to the cart at once.

I’d rather not use an app for this, as it adds extra loading time and code.

{{ 'variant-details.css' | asset_url | stylesheet_tag }}
{%- liquid
  assign variants_available_arr = product.variants | map: 'available'
  assign variants_option1_arr = product.variants | map: 'option1'
  assign variants_option2_arr = product.variants | map: 'option2'
  assign variants_option3_arr = product.variants | map: 'option3'
  assign variant_id = product_variants | map: 'id'
   
  assign product_form_id = 'product-form-' | append: section.id
-%}
{%- for value in option.values -%}
  {%- liquid
    assign option_disabled = true

    assign price = product.selected_or_first_available_variant.price
     
     for option1_name in variants_option1_arr
      case option.position
        when 1
          if variants_option1_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
            assign option_disabled = false
          endif
        when 2
          if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
            assign option_disabled = false
          endif
        when 3
          if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == product.selected_or_first_available_variant.option2 and variants_option3_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
            assign option_disabled = false
          endif
      endcase
    endfor
  -%}
  {%- if block.settings.picker_type == 'details' -%}

  <div class="variant-detail" id="{{ section.id }}-{{ forloop.index0 }}">
  <div class="detail-radio" id="{{ value }}"><input type="radio" id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}" name="{{ option.name }}" value="{{ value | escape }}" form="{{ product_form_id }}" {% if option.selected_value == value %} checked {% endif %} {% if option_disabled %} class="disabled" {% endif %}
    >
    {% if option.name == 'Colour' and block.settings.show_colorswatch %}
      {%- liquid
          assign color_file_name = value | handle | append: '.' | append: 'png'
          assign swatchimage = color_file_name | file_img_url: '50x50' | prepend: 'https:' | split: '?' | first
          assign colorswatchvalue = value | downcase | replace: ' ', ''
      -%}
      
      <label class="color-swatchimg color-swatch {% if option.selected_value == value %} active{% endif %}"
              for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
              data-val="{{ value }}"
              style="background-color: {{ colorswatchvalue }};{% if images[color_file_name] != blank %}  background-image: url({{ swatchimage }});{% endif %}">{{ value }}
        <span class="visually-hidden">{{ 'products.product.variant_sold_out_or_unavailable' | t }}</span>
      </label>
    {% else %}
      <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
        {{ value -}}
        <span class="visually-hidden">{{ 'products.product.variant_sold_out_or_unavailable' | t }}</span>
      </label>
    {% endif %}
  </div>
  <div class="detail-price" id="{{ value }}">
  {% for price in prices %}
    {% if customer %}
    {{ price | money_without_trailing_zeros }}
  {% else %}
  <b><a href="https://shopify.com/69175083231/account">Log in</a> for pricing</b>
  {% endif %}
  {% endfor %}
  </div>
 {% if customer %}
  <div class="detail-qty" id="{{ forloop.index0 }}">
                  <quantity-input class="quantity" data-url="{{ product.url }}" data-section="{{ section.id }}">
                  <button class="quantity__button no-js-hidden" name="minus" type="button">
                    <span class="visually-hidden">
                      {{- 'products.product.quantity.decrease' | t: product: product.title | escape -}}
                    </span>
                    {% render 'icon-minus' %}
                  </button>
                  <input
                    class="quantity__input"
                    type="number"
                    name="quantity"
                    id="Quantity-{{ section.id }}"
                    data-cart-quantity="{{ cart_qty }}"
                    data-min="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
                    min="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
                    {% if product.selected_or_first_available_variant.quantity_rule.max != null %}
                      data-max="{{ product.selected_or_first_available_variant.quantity_rule.max }}"
                      max="{{ product.selected_or_first_available_variant.quantity_rule.max }}"
                    {% endif %}
                    step="{{ product.selected_or_first_available_variant.quantity_rule.increment }}"
                    value="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
                    form="{{ product_form_id }}"
                  />
                  <button class="quantity__button no-js-hidden" name="plus" type="button">
                    <span class="visually-hidden">
                      {{- 'products.product.quantity.increase' | t: product: product.title | escape -}}
                    </span>
                    {% render 'icon-plus' %}
                  </button>
                </quantity-input>  
  </div>
   <div class="detail-submit"> 
     <form action="/cart/add" method="post" id="product-form- {{ variant_id }}">
     <input type="hidden" name="id" value="{{ variant_id }}">
     <div>
     <button type="submit" name="add">Add to cart</button>
</div>
</form>
   </div>
{% endif %}
    
</div>

    
  {%- elsif block.settings.picker_type == 'dropdown' -%}
    <option
      value="{{ value | escape }}"
      {% if option.selected_value == value %}
        selected="selected"
      {% endif %}
    >
      {% if option_disabled -%}
        {{- 'products.product.value_unavailable' | t: option_value: value -}}
      {%- else -%}
        {{- value -}}
      {%- endif %}
    </option>
  {%- endif -%}
{%- endfor -%}
.variant-details .no-js-hidden variant__order {
  box-shadow: 5px 10px #888888;
}
.option-label {
    width: 100%;
    display: flex;
    padding-left: 0.2rem;
}

.variant-details {
  border: solid;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 0.5rem;
  box-shadow: 0px 0px 20px 1px #88888836;
  border-color: #007180;
  overflow-y: scroll;
  position: relative;
  max-height: calc(100vh - 18rem);
  height: auto;
}

.variant-detail {
  display: flex;
  padding: 0.5rem;
  justify-content: space-between;
  border-bottom: groove;
  border-bottom-color: #00BCD4;
  font-size: large;
  align-items: center;
}

.variant-detail:last-child {
  border-bottom: none;
  padding-bottom: 0px;;
}

.form__label-details {
  margin-left: 1rem;
}

.detail-radio {
width: 50%;
display: flex;
}

.detail-price {
    display: flex;
    justify-content: center;
    align-items: center;
}

.detail-radio .product-form__input input[type=radio]:checked+label, .product__info-wrapper .product-form__input input[type=radio]:checked+label {
    background-color: #007180 !important; 
    color: #FFFFFF !important;
    border-color: rgb(var(--color-link-hover)) !important; 
}

.detail-radio label {
font-size: calc(var(--font-body-scale)* 18px) !important;  
}

#text {
  display: none;
}
{% comment %}
  Renders product variant-picker

  Accepts:
  - product: {Object} product object.
  - block: {Object} passing the block information.
  - product_form_id: {String} Id of the product form to which the variant picker is associated.
  - update_url: {Boolean} whether or not to update url when changing variants. If false, the url isn't updated. Default: true (optional).
  Usage:
  {% render 'product-variant-picker', product: product, block: block, product_form_id: product_form_id %}
{% endcomment %}
{%- unless product.has_only_default_variant -%}
    {%- if block.settings.picker_type == 'button' -%}
        <variant-radios
            id="variant-radios-{{ section.id }}"
            class="no-js-hidden variant__order"
            data-section="{{ section.id }}"
            data-url="{{ product.url }}"
            data-layout="{{ block.settings.picker_type }}"
            {% if update_url == false %}
                data-update-url="false"
            {% endif %}
            {{ block.shopify_attributes }}>

            {%- for option in product.options_with_values -%}
                <fieldset {% if option.name == 'Color' and block.settings.show_colorswatch %} class="js product_form_input swatchComponent inner-class" {% else %} class="js product-form__input product_form_input inner-class" {% endif %}>
                    <legend class="form__label">{{ option.name }}:
                        {% assign current_variant = product.selected_or_first_available_variant %}
                        {% if current_variant.option.selected_value != '' %}
                          <span>{{ option.selected_value }}</span>
                        {% endif %}
                     </legend>
                    <div {% if option.name == 'Color' and block.settings.show_colorswatch %} class="wbswatchclr" {% endif %}>
                        {% render 'product-variant-options', product: product, option: option, block: block %}
                    </div>
                </fieldset>
            {%- endfor -%}
            <script type="application/json">
                {{ product.variants | json }}
            </script>
        </variant-radios>
    {%- elsif block.settings.picker_type == 'dropdown' -%}
        <variant-selects
            id="variant-selects-{{ section.id }}"
            class="no-js-hidden"
            data-section="{{ section.id }}"
            data-url="{{ product.url }}"
            data-layout="{{ block.settings.picker_type }}"
            {% if update_url == false %}
                data-update-url="false"
            {% endif %}
            {{ block.shopify_attributes }}
        >
            {%- for option in product.options_with_values -%}
                <div class="product-form__input product_form_input product-form__input--dropdown">
                    <legend class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}">{{ option.name }}:</legend>
                    <div class="select">
                        <select
                                id="Option-{{ section.id }}-{{ forloop.index0 }}"
                                class="select__select"
                                name="options[{{ option.name | escape }}]"
                                aria-label="{{ option.name }}"
                                form="{{ product_form_id }}"
                        >
                            {% render 'product-variant-options', product: product, option: option, block: block %}
                        </select>
                        {% render 'icon-caret' %}
                    </div>
                </div>
            {%- endfor -%}

            <script type="application/json">
        {{ product.variants | json }}

            </script>
        </variant-selects> 
      {% elsif block.settings.picker_type == 'details' %}
        <variant-details
            class="no-js-hidden variant__order"
            data-section="{{ section.id }}"
            data-url="{{ product.url }}"
            data-layout="{{ block.settings.picker_type }}"
            {% if update_url == false %}
                data-update-url="false"
            {% endif %}
            {{ block.shopify_attributes }}>  
            {%- for option in product.options_with_values -%}
                <fieldset {% if option.name == 'Color' and block.settings.show_colorswatch %} class="js product_form_input swatchComponent inner-class" {% else %} class="js product-form__input product_form_input inner-class" {% endif %}>
                {% if block.settings.picker_type == 'details' %}    
                <div class="option-label">
                  <legend class="form__label-details"><b>{{ option.name }}:</b></legend>
                </div> 
                  {% else %}  
                  <legend class="form__label">{{ option.name }}:
                        {% assign current_variant = product.selected_or_first_available_variant %}
                        {% if current_variant.option.selected_value != '' %}
                          <span>{{ option.selected_value }}</span>
                        {% endif %}
                     </legend>
                 
                  {% endif %}
                  <div class="variant-details" id="{{ section.id }}" {% if option.name == 'Color' and block.settings.show_colorswatch %} class="wbswatchclr" {% endif %}>
                    {% render 'product-variant-details', product: product, option: option, block: block %}  
                  </div>
                </fieldset>
            {%- endfor -%}
            <script type="application/json">
                {{ product.variants | json }}
            </script>
        </variant-details>
      {%- endif -%}
{%- endunless -%}

<noscript class="product-form__noscript-wrapper-{{ section.id }}">
    <div class="product-form__input product_form_input{% if product.has_only_default_variant %} hidden{% endif %}">
        <label class="form__label" for="Variants-{{ section.id }}">
            {{- 'products.product.product_variants' | t -}}
        </label>
        <div class="select">
            <select
                    name="id"
                    id="Variants-{{ section.id }}"
                    class="select__select"
                    form="{{ product_form_id }}"
            >
                {%- for variant in product.variants -%}
                    <option {% if variant == product.selected_or_first_available_variant %} selected="selected" {% endif %} {% if variant.available == false %} disabled {% endif %} value="{{ variant.id }}" >
                        {%- liquid
                            echo variant.title
                            echo variant.price | money | strip_html | prepend: ' - '
                            if variant.available == false
                                echo 'products.product.sold_out' | t | prepend: ' - '
                            endif
                            if variant.quantity_rule.increment > 1
                                echo 'products.product.quantity.multiples_of' | t: quantity: variant.quantity_rule.increment | prepend: ' - '
                            endif
                            if variant.quantity_rule.min > 1
                                echo 'products.product.quantity.minimum_of' | t: quantity: variant.quantity_rule.min | prepend: ' - '
                            endif
                            if variant.quantity_rule.max != null
                                echo 'products.product.quantity.maximum_of' | t: quantity: variant.quantity_rule.max | prepend: ' - '
                            endif
                            # TODO: enable theme-check once `item_count_for_variant` is accepted as valid filter
                            # theme-check-disable
                            assign cart_quantity = cart | item_count_for_variant: variant.id
                            # theme-check-enable
                            if cart_quantity > 0
                                echo 'products.product.quantity.in_cart_html' | t: quantity: cart_quantity | prepend: ' - '
                            endif
                        -%}
                    </option>
                {%- endfor -%}
            </select>
            {% render 'icon-caret' %}
        </div>
    </div>
</noscript> 

Update: I’ve got the variant id’s appending properly using the standard for loop, however I’m getting this.

and it’s not honouring the quantity selector or triggering the popup cart.

Now it’s like this and i’ve lost the price:

{{ 'variant-details.css' | asset_url | stylesheet_tag }}
{%- liquid
  assign variants_available_arr = product.variants | map: 'available'
  assign variants_option1_arr = product.variants | map: 'option1'
  assign variants_option2_arr = product.variants | map: 'option2'
  assign variants_option3_arr = product.variants | map: 'option3'
  assign variant_id = product.variants | map: 'id'
  assign variant_url = product.variants | map: 'url'
   
  assign product_form_id = 'product-form-' | append: section.id
-%}
{%- for value in option.values -%}
    {%- liquid
    assign option_disabled = true

    assign price = product.selected_or_first_available_variant.price
     
     for option1_name in variants_option1_arr
      case option.position
        when 1
          if variants_option1_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
            assign option_disabled = false
          endif
        when 2
          if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
            assign option_disabled = false
          endif
        when 3
          if option1_name == product.selected_or_first_available_variant.option1 and variants_option2_arr[forloop.index0] == product.selected_or_first_available_variant.option2 and variants_option3_arr[forloop.index0] == value and variants_available_arr[forloop.index0]
            assign option_disabled = false
          endif
      endcase
    endfor
    
  -%}
  {%- if block.settings.picker_type == 'details' -%}
  
  

    {% if option.name == 'Colour' and block.settings.show_colorswatch %}
      {%- liquid
          assign color_file_name = value | handle | append: '.' | append: 'png'
          assign swatchimage = color_file_name | file_img_url: '50x50' | prepend: 'https:' | split: '?' | first
          assign colorswatchvalue = value | downcase | replace: ' ', ''
      -%}
      
      
    {% else %}
      
    {% endif %}
  

  
  {% for price in prices %}
    {% if customer %}
    {{ price | money_without_trailing_zeros }}
  {% else %}
  **[Log in](https://shopify.com/69175083231/account) for pricing**
  {% endif %}
  {% endfor %}
  

 {% if customer %}
  {% for id in variant_id %}
    {% for url in variant_url %}
   
                  
                 
   
 
 {% endfor %}
       {% endfor %}
{% endif %}
    

    
  {%- elsif block.settings.picker_type == 'dropdown' -%}
    
  {%- endif -%}  
{%- endfor -%}