Quick add to cart on Product Item 'variant problem'

I’ve added a ‘quick add’ option into my product-item.liquid. So when users are on the collection page, they can click the quick add button to add to cart. This works great however it only ‘adds to cart’ the first variant of the product, not the variant selected.

Is there anyway to make it add to cart the variant that is selected?

I am using the prestige theme.

This is the code i added :

1 Like

@LilyGatman

Sorry you are facing this issue, it would be my pleasure to help you.

Welcome to the Shopify community! :blush:
Thanks for your good question.

Please share your site URL,
I will check out the issue and provide you a solution here.

Heres the URL https://lilygatman.myshopify.com/

Click on the ‘Cups’ link in the nav bar and then hover over the products, the ‘quick add’ option will pop up.

Thanks.

1 Like

@LilyGatman

yes its possible customization code

@KetanKumar

Is there an easy solution?

1 Like

Hi @LilyGatman ,

Please send me the code of the product item file, where you add the form code. Iwill help you to change and add the JS so that when ‘ColorSwatchItem’ is clicked, it will change the value of name=“id” in the form and you can can add to cart exact variant.

@LilyGatman

yes, sure If you’re comfortable working with coding languages (eg. HTML, JavaScript, CSS, and Liquid), then you can try to follow the custom coding provided by Quick View

1 Like

@LitCommerce

Ok, here is the product item file.

The custom quick add option is at the bottom of the code.


  

    

      {%- comment -%}
      We are using LazySizes to efficiently choose the most appropriate image in the set. However, because internally LazySizes uses srcset, we need to make
      sure that the image sizes we offer is not larger than the max size uploaded by the merchants.
      {%- endcomment -%}

      {%- if settings.product_image_size == 'natural' or use_horizontal -%}
        {%- assign use_natural_size = true -%}
      {%- else -%}
        {%- assign use_natural_size = false -%}
      {%- endif -%}

      {%- if settings.product_show_secondary_image and product.media[1] != blank and use_horizontal != true -%}
        {%- assign has_alternate_image = true -%}
      {%- else -%}
        {%- assign has_alternate_image = false -%}
      {%- endif -%}

      
        {%- if use_horizontal -%}
          {%- assign max_width = 125 -%}
        {%- else -%}
          {%- assign max_width = product.featured_media.preview_image.width -%}
        {%- endif -%}

        {%- assign media_aspect_ratio = product.featured_media.aspect_ratio | default: product.featured_media.preview_image.aspect_ratio -%}

        

          {%- comment -%}
          IMPLEMENTATION NOTE: The alternate image (not visible by default) should be the first in the DOM, as the spinner (Image__Loader element) is
          displayed based on the immediately previously shown image.
          {%- endcomment -%}

          {%- if has_alternate_image -%}
            {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,300,400,600,800,900,1000,1200', image: product.media[1] -%}{%- endcapture -%}

            {%- assign image_url = product.media[1] | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}

            
          {%- endif -%}

          {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,400,600,700,800,900,1000,1200', image: product.featured_media -%}{%- endcapture -%}
          {%- assign image_url = product.featured_media | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}

          
          

          
        

      

      {%- if show_labels -%}
        {%- capture product_labels -%}
          {%- for tag in product.tags -%}
            {%- if tag contains '__label' -%}
              {{ tag | split: '__label:' | last }}
              {%- break -%}
            {%- endif -%}
          {%- endfor -%}

          {%- if product.available -%}
            {%- if product.compare_at_price > product.price -%}
              {{ 'product.labels.on_sale' | t }}
            {%- endif -%}
          {%- else -%}
            {{ 'product.labels.sold_out' | t }}
          {%- endif -%}
        {%- endcapture -%}

        {%- if product_labels != blank -%}
          

            {{ product_labels }}
          

        {%- endif -%}
      {%- endif -%}

      {%- if show_product_info -%}					
        
          {%- if show_vendor -%}
            

{{ product.vendor }}

          {%- endif -%}

          ## 
            {{ product.title }}
          

          {%- if settings.show_product_rating -%}
            {%- unless use_horizontal -%}
              
                {%- render 'product-rating', product: product -%}
              

            {%- endunless -%}
          {%- endif -%}
                  
          {%- if show_color_swatch == false -%}
            {%- assign color_swatch_list = '' -%}

            {%- capture color_swatch -%}
              {%- assign color_label = 'color,colour,couleur,colore,farbe,색,色,färg,farve' | split: ',' -%}
              {%- assign color_swatch_config = settings.color_swatch_config | newline_to_br | split: '
' -%}
              {%- capture color_name -%}{{ section.id }}-{{ product.id }}{%- endcapture -%}

              {%- for option in product.options_with_values -%}
                {%- assign downcased_option = option.name | downcase -%}

                {%- if color_label contains downcased_option -%}
                  {%- assign variant_option = 'option' | append: forloop.index -%}

                  {%- for value in option.values -%}
                    {%- assign downcased_value = value | downcase -%}
                    {%- capture color_id -%}{{ section.id }}-{{ product.id }}-{{ forloop.index }}{%- endcapture -%}

                    {%- for variant in product.variants -%}
                      {%- if variant[variant_option] == value -%}
                        {%- assign variant_for_value = variant -%}
                        {%- break -%}
                      {%- endif -%}
                    {%- endfor -%}

                    

                      {%- if variant_for_value.image -%}
                        {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,400,600,700,800,900,1000,1200', image: variant_for_value.image -%}{%- endcapture -%}
                        {%- assign variant_image_url = variant_for_value.image | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}
                      {%- endif -%}

                      
                      
                    

                  {%- endfor -%}
                {%- endif -%}
              {%- endfor -%}
            {%- endcapture -%}

            {%- if color_swatch != blank -%}
              {%- capture color_swatch_list -%}
                
                  {{- color_swatch -}}
                

              {%- endcapture -%}
            {%- endif -%}
          {%- endif -%}

          {%- if show_price_on_hover == nil -%}
            {%- assign show_price_on_hover = settings.product_show_price_on_hover -%}
          {%- endif -%}

          {%- if show_price_on_hover and color_swatch_list != blank -%}
            {{- color_swatch_list -}}
          {%- endif -%}

          {%- if product.template_suffix != 'coming-soon' -%}
            
              {%- if product.compare_at_price > product.price -%}
                {%- if settings.currency_code_enabled -%}
                  {{ product.price | money_with_currency }}
                  {{ product.compare_at_price | money_with_currency }}
                {%- else -%}
                  {{ product.price | money }}
                  {{ product.compare_at_price | money }}
                {%- endif -%}
              {%- elsif product.price_varies -%}
                {%- if settings.currency_code_enabled -%}
                  {%- capture formatted_min_price -%}{{ product.price_min | money_with_currency }}{%- endcapture -%}
                  {%- capture formatted_max_price -%}{{ product.price_max | money_with_currency }}{%- endcapture -%}
                {%- else -%}
                  {%- capture formatted_min_price -%}{{ product.price_min | money }}{%- endcapture -%}
                  {%- capture formatted_max_price -%}{{ product.price_max | money }}{%- endcapture -%}
                {%- endif -%}

                {{ 'collection.product.from_price_html' | t: min_price: formatted_min_price, max_price: formatted_max_price }}
              {%- else -%}
                {%- if settings.currency_code_enabled -%}
                  {{ product.price | money_with_currency }}
                {%- else -%}
                  {{ product.price | money }}
                {%- endif -%}
              {%- endif -%}
            

            {%- if product.selected_or_first_available_variant.unit_price_measurement -%}
              
                

                  {{ product.selected_or_first_available_variant.unit_price | money }}
                  / 

                  
                    {{- product.selected_or_first_available_variant.unit_price_measurement.reference_value -}}
                  

                  {{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
                

              

            {%- endif -%}
          {%- endif -%}

          {%- if show_price_on_hover == false and color_swatch_list != blank -%}
            {{- color_swatch_list -}}
          {%- endif -%}
        

      {%- endif -%}
    

    {%- if use_horizontal -%}
      {{ 'collection.product.view_product' | t }}
    {%- endif -%}
    

    
    

      
      

        
        
        
      

      
  	

    
  

@LitCommerce

Ok, here is the product item file.

The custom quick add option is at the bottom of the code.


  

    

      {%- comment -%}
      We are using LazySizes to efficiently choose the most appropriate image in the set. However, because internally LazySizes uses srcset, we need to make
      sure that the image sizes we offer is not larger than the max size uploaded by the merchants.
      {%- endcomment -%}

      {%- if settings.product_image_size == 'natural' or use_horizontal -%}
        {%- assign use_natural_size = true -%}
      {%- else -%}
        {%- assign use_natural_size = false -%}
      {%- endif -%}

      {%- if settings.product_show_secondary_image and product.media[1] != blank and use_horizontal != true -%}
        {%- assign has_alternate_image = true -%}
      {%- else -%}
        {%- assign has_alternate_image = false -%}
      {%- endif -%}

      
        {%- if use_horizontal -%}
          {%- assign max_width = 125 -%}
        {%- else -%}
          {%- assign max_width = product.featured_media.preview_image.width -%}
        {%- endif -%}

        {%- assign media_aspect_ratio = product.featured_media.aspect_ratio | default: product.featured_media.preview_image.aspect_ratio -%}

        

          {%- comment -%}
          IMPLEMENTATION NOTE: The alternate image (not visible by default) should be the first in the DOM, as the spinner (Image__Loader element) is
          displayed based on the immediately previously shown image.
          {%- endcomment -%}

          {%- if has_alternate_image -%}
            {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,300,400,600,800,900,1000,1200', image: product.media[1] -%}{%- endcapture -%}

            {%- assign image_url = product.media[1] | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}

            
          {%- endif -%}

          {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,400,600,700,800,900,1000,1200', image: product.featured_media -%}{%- endcapture -%}
          {%- assign image_url = product.featured_media | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}

          
          

          
        

      

      {%- if show_labels -%}
        {%- capture product_labels -%}
          {%- for tag in product.tags -%}
            {%- if tag contains '__label' -%}
              {{ tag | split: '__label:' | last }}
              {%- break -%}
            {%- endif -%}
          {%- endfor -%}

          {%- if product.available -%}
            {%- if product.compare_at_price > product.price -%}
              {{ 'product.labels.on_sale' | t }}
            {%- endif -%}
          {%- else -%}
            {{ 'product.labels.sold_out' | t }}
          {%- endif -%}
        {%- endcapture -%}

        {%- if product_labels != blank -%}
          

            {{ product_labels }}
          

        {%- endif -%}
      {%- endif -%}

      {%- if show_product_info -%}					
        
          {%- if show_vendor -%}
            

{{ product.vendor }}

          {%- endif -%}

          ## 
            {{ product.title }}
          

          {%- if settings.show_product_rating -%}
            {%- unless use_horizontal -%}
              
                {%- render 'product-rating', product: product -%}
              

            {%- endunless -%}
          {%- endif -%}
                  
          {%- if show_color_swatch == false -%}
            {%- assign color_swatch_list = '' -%}

            {%- capture color_swatch -%}
              {%- assign color_label = 'color,colour,couleur,colore,farbe,색,色,färg,farve' | split: ',' -%}
              {%- assign color_swatch_config = settings.color_swatch_config | newline_to_br | split: '
' -%}
              {%- capture color_name -%}{{ section.id }}-{{ product.id }}{%- endcapture -%}

              {%- for option in product.options_with_values -%}
                {%- assign downcased_option = option.name | downcase -%}

                {%- if color_label contains downcased_option -%}
                  {%- assign variant_option = 'option' | append: forloop.index -%}

                  {%- for value in option.values -%}
                    {%- assign downcased_value = value | downcase -%}
                    {%- capture color_id -%}{{ section.id }}-{{ product.id }}-{{ forloop.index }}{%- endcapture -%}

                    {%- for variant in product.variants -%}
                      {%- if variant[variant_option] == value -%}
                        {%- assign variant_for_value = variant -%}
                        {%- break -%}
                      {%- endif -%}
                    {%- endfor -%}

                    

                      {%- if variant_for_value.image -%}
                        {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,400,600,700,800,900,1000,1200', image: variant_for_value.image -%}{%- endcapture -%}
                        {%- assign variant_image_url = variant_for_value.image | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}
                      {%- endif -%}

                      
                      
                    

                  {%- endfor -%}
                {%- endif -%}
              {%- endfor -%}
            {%- endcapture -%}

            {%- if color_swatch != blank -%}
              {%- capture color_swatch_list -%}
                
                  {{- color_swatch -}}
                

              {%- endcapture -%}
            {%- endif -%}
          {%- endif -%}

          {%- if show_price_on_hover == nil -%}
            {%- assign show_price_on_hover = settings.product_show_price_on_hover -%}
          {%- endif -%}

          {%- if show_price_on_hover and color_swatch_list != blank -%}
            {{- color_swatch_list -}}
          {%- endif -%}

          {%- if product.template_suffix != 'coming-soon' -%}
            
              {%- if product.compare_at_price > product.price -%}
                {%- if settings.currency_code_enabled -%}
                  {{ product.price | money_with_currency }}
                  {{ product.compare_at_price | money_with_currency }}
                {%- else -%}
                  {{ product.price | money }}
                  {{ product.compare_at_price | money }}
                {%- endif -%}
              {%- elsif product.price_varies -%}
                {%- if settings.currency_code_enabled -%}
                  {%- capture formatted_min_price -%}{{ product.price_min | money_with_currency }}{%- endcapture -%}
                  {%- capture formatted_max_price -%}{{ product.price_max | money_with_currency }}{%- endcapture -%}
                {%- else -%}
                  {%- capture formatted_min_price -%}{{ product.price_min | money }}{%- endcapture -%}
                  {%- capture formatted_max_price -%}{{ product.price_max | money }}{%- endcapture -%}
                {%- endif -%}

                {{ 'collection.product.from_price_html' | t: min_price: formatted_min_price, max_price: formatted_max_price }}
              {%- else -%}
                {%- if settings.currency_code_enabled -%}
                  {{ product.price | money_with_currency }}
                {%- else -%}
                  {{ product.price | money }}
                {%- endif -%}
              {%- endif -%}
            

            {%- if product.selected_or_first_available_variant.unit_price_measurement -%}
              
                

                  {{ product.selected_or_first_available_variant.unit_price | money }}
                  / 

                  
                    {{- product.selected_or_first_available_variant.unit_price_measurement.reference_value -}}
                  

                  {{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
                

              

            {%- endif -%}
          {%- endif -%}

          {%- if show_price_on_hover == false and color_swatch_list != blank -%}
            {{- color_swatch_list -}}
          {%- endif -%}
        

      {%- endif -%}
    

    {%- if use_horizontal -%}
      {{ 'collection.product.view_product' | t }}
    {%- endif -%}
    

    
    

      
      

        
        
        
      

      
  	

    
  

Hi @LilyGatman ,

Please change code:


  

    

      {%- comment -%}
      We are using LazySizes to efficiently choose the most appropriate image in the set. However, because internally LazySizes uses srcset, we need to make
      sure that the image sizes we offer is not larger than the max size uploaded by the merchants.
      {%- endcomment -%}

      {%- if settings.product_image_size == 'natural' or use_horizontal -%}
        {%- assign use_natural_size = true -%}
      {%- else -%}
        {%- assign use_natural_size = false -%}
      {%- endif -%}

      {%- if settings.product_show_secondary_image and product.media[1] != blank and use_horizontal != true -%}
        {%- assign has_alternate_image = true -%}
      {%- else -%}
        {%- assign has_alternate_image = false -%}
      {%- endif -%}

      
        {%- if use_horizontal -%}
          {%- assign max_width = 125 -%}
        {%- else -%}
          {%- assign max_width = product.featured_media.preview_image.width -%}
        {%- endif -%}

        {%- assign media_aspect_ratio = product.featured_media.aspect_ratio | default: product.featured_media.preview_image.aspect_ratio -%}

        

          {%- comment -%}
          IMPLEMENTATION NOTE: The alternate image (not visible by default) should be the first in the DOM, as the spinner (Image__Loader element) is
          displayed based on the immediately previously shown image.
          {%- endcomment -%}

          {%- if has_alternate_image -%}
            {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,300,400,600,800,900,1000,1200', image: product.media[1] -%}{%- endcapture -%}

            {%- assign image_url = product.media[1] | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}

            
          {%- endif -%}

          {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,400,600,700,800,900,1000,1200', image: product.featured_media -%}{%- endcapture -%}
          {%- assign image_url = product.featured_media | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}

          
          

          
        

      

      {%- if show_labels -%}
        {%- capture product_labels -%}
          {%- for tag in product.tags -%}
            {%- if tag contains '__label' -%}
              {{ tag | split: '__label:' | last }}
              {%- break -%}
            {%- endif -%}
          {%- endfor -%}

          {%- if product.available -%}
            {%- if product.compare_at_price > product.price -%}
              {{ 'product.labels.on_sale' | t }}
            {%- endif -%}
          {%- else -%}
            {{ 'product.labels.sold_out' | t }}
          {%- endif -%}
        {%- endcapture -%}

        {%- if product_labels != blank -%}
          

            {{ product_labels }}
          

        {%- endif -%}
      {%- endif -%}

      {%- if show_product_info -%}					
        
          {%- if show_vendor -%}
            

{{ product.vendor }}

          {%- endif -%}

          ## 
            {{ product.title }}
          

          {%- if settings.show_product_rating -%}
            {%- unless use_horizontal -%}
              
                {%- render 'product-rating', product: product -%}
              

            {%- endunless -%}
          {%- endif -%}
                  
          {%- if show_color_swatch == false -%}
            {%- assign color_swatch_list = '' -%}

            {%- capture color_swatch -%}
              {%- assign color_label = 'color,colour,couleur,colore,farbe,색,色,färg,farve' | split: ',' -%}
              {%- assign color_swatch_config = settings.color_swatch_config | newline_to_br | split: '
' -%}
              {%- capture color_name -%}{{ section.id }}-{{ product.id }}{%- endcapture -%}

              {%- for option in product.options_with_values -%}
                {%- assign downcased_option = option.name | downcase -%}

                {%- if color_label contains downcased_option -%}
                  {%- assign variant_option = 'option' | append: forloop.index -%}

                  {%- for value in option.values -%}
                    {%- assign downcased_value = value | downcase -%}
                    {%- capture color_id -%}{{ section.id }}-{{ product.id }}-{{ forloop.index }}{%- endcapture -%}

                    {%- for variant in product.variants -%}
                      {%- if variant[variant_option] == value -%}
                        {%- assign variant_for_value = variant -%}
          				{%- assign variant_id = variant.id -%}
                        {%- break -%}
                      {%- endif -%}
                    {%- endfor -%}

                    

                      {%- if variant_for_value.image -%}
                        {%- capture supported_sizes -%}{%- render 'image-size', sizes: '200,400,600,700,800,900,1000,1200', image: variant_for_value.image -%}{%- endcapture -%}
                        {%- assign variant_image_url = variant_for_value.image | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}
                      {%- endif -%}

                      
                      
                    

                  {%- endfor -%}
                {%- endif -%}
              {%- endfor -%}
            {%- endcapture -%}

            {%- if color_swatch != blank -%}
              {%- capture color_swatch_list -%}
                
                  {{- color_swatch -}}
                

              {%- endcapture -%}
            {%- endif -%}
          {%- endif -%}

          {%- if show_price_on_hover == nil -%}
            {%- assign show_price_on_hover = settings.product_show_price_on_hover -%}
          {%- endif -%}

          {%- if show_price_on_hover and color_swatch_list != blank -%}
            {{- color_swatch_list -}}
          {%- endif -%}

          {%- if product.template_suffix != 'coming-soon' -%}
            
              {%- if product.compare_at_price > product.price -%}
                {%- if settings.currency_code_enabled -%}
                  {{ product.price | money_with_currency }}
                  {{ product.compare_at_price | money_with_currency }}
                {%- else -%}
                  {{ product.price | money }}
                  {{ product.compare_at_price | money }}
                {%- endif -%}
              {%- elsif product.price_varies -%}
                {%- if settings.currency_code_enabled -%}
                  {%- capture formatted_min_price -%}{{ product.price_min | money_with_currency }}{%- endcapture -%}
                  {%- capture formatted_max_price -%}{{ product.price_max | money_with_currency }}{%- endcapture -%}
                {%- else -%}
                  {%- capture formatted_min_price -%}{{ product.price_min | money }}{%- endcapture -%}
                  {%- capture formatted_max_price -%}{{ product.price_max | money }}{%- endcapture -%}
                {%- endif -%}

                {{ 'collection.product.from_price_html' | t: min_price: formatted_min_price, max_price: formatted_max_price }}
              {%- else -%}
                {%- if settings.currency_code_enabled -%}
                  {{ product.price | money_with_currency }}
                {%- else -%}
                  {{ product.price | money }}
                {%- endif -%}
              {%- endif -%}
            

            {%- if product.selected_or_first_available_variant.unit_price_measurement -%}
              
                

                  {{ product.selected_or_first_available_variant.unit_price | money }}
                  / 

                  
                    {{- product.selected_or_first_available_variant.unit_price_measurement.reference_value -}}
                  

                  {{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
                

              

            {%- endif -%}
          {%- endif -%}

          {%- if show_price_on_hover == false and color_swatch_list != blank -%}
            {{- color_swatch_list -}}
          {%- endif -%}
        

      {%- endif -%}
    

    {%- if use_horizontal -%}
      {{ 'collection.product.view_product' | t }}
    {%- endif -%}
    

    
    

      
      

        
        
        
      

      
  	

    
  

And go to custom.js file, add code:

document.querySelectorAll('.ColorSwatch__Radio').forEach(
  (input) => input.addEventListener('click', this.onButtonClick.bind(this))
);
function onButtonClick(event) {
  event.preventDefault();
  
  const idForm = event.target.dataset.productFormId;
  const idVariant = event.target.dataset.variantId;
  document.getElementById(idForm).value = idVariant;
}

Hope it helps!

1 Like

Thanks @LitCommerce the functionality works great, but i noticed now when i select another colour variant, the :focus border doesn’t change to the variant selected. It stays on the first variant.

It seems to just be the added javascript that is making this happen. The :focus border works when I take out the added javascript.

To be more specific here’s a screenshot of the first variant having a :focus border on it.

Hi @LilyGatman ,

Please remove code here:

If it helped you solve your issue, please mark it as a solution. Thank you and good luck.