Automatically Open Cart Drawer when using Bulk Option for Quick Add

Hi All

I have tried a few different themes (Dawn, Trade, Refresh) from Shopify and all work the same way:

I have the cart type set to Drawer

I have the Quick Add option set to “Bulk” instead of “Standard” for featured collections on Home Page as well as on Collections Page, so instead of “Add to Cart” it gives you the quantity selector option.

On updating quantity (add / remove items), the cart gets updated but the cart drawer does not open up / slide out.

If the Quick Add option is changed to “Standard” (Add to Cart button) instead of “Bulk” , clicking on that button slides out the cart drawer. I am trying to replicate that experience with the “Bulk” option for Quick Add so its clear to users that their cart has been updated (items added / removed) instead of having to check the cart icon at the top of the page.

Any code help to change this is greatly appreciated

I understand the challenge you’re facing with the “Bulk” Quick Add option not triggering the cart drawer to open. What you want is for the cart drawer to open automatically whenever the quantity is updated. Here’s a way to achieve this with a bit of custom Javascript:

  1. Edit the theme code: Go to your Shopify admin, then “Online Store” > “Themes” > “Actions” > “Edit code.”

  2. Find the JavaScript file: Locate the main JavaScript file in the “Assets” folder, usually named something like theme.js or custom.js.

  3. Add custom JavaScript: At the end of this JavaScript file, add the following code to trigger the cart drawer when quantities are updated:

document.addEventListener('DOMContentLoaded', function() {
  function openCartDrawer() {
    // Assuming the cart drawer opens with a class toggle
    const cartDrawer = document.querySelector('.cart-drawer');
    if (cartDrawer) {
      cartDrawer.classList.add('is-open'); // Adjust the class based on your theme
    }
  }

  document.querySelectorAll('.quantity-selector').forEach(function(el) {
    el.addEventListener('change', function() {
      // Assuming quantity changes via an input or select element
      // Trigger the cart update logic here (this might vary based on your theme)
      // Example: trigger a click event on the "Add to Cart" button if needed
      // document.querySelector('.add-to-cart-button').click();
      
      // Open the cart drawer
      openCartDrawer();
    });
  });
});

Adjust for your theme: You might need to tweak the class names or the logic depending on how your theme handles the cart drawer and quantity updates

<style>
.progress_bar {
    position: fixed;
    bottom: 15px;
    background: #ffffff;
    width: 100%;
    margin: auto;
    border: 1px solid #d9d9d9;
    z-index: 999999999999;
    font-weight: 600;
    font-size: 18px;
}

.progress_bar_container {
    display: flex;
    align-items: center;
}

.step_s {
    padding: 20px;
    width: 33.33%;
    text-align: center;
}

.step_s.this_active {
    background: #f4ffb8;
    color: #000000;
}

.done_svg {
display:none;
}

.step_s.this_active span.done_svg {
    display: block;
}

.step_s {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.product_wrapper {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
}
.product_button {
    display: flex;
    align-items: center;
    justify-content: space-around;
}
.product_inner {
    border: 1px solid #ebebeb;
    padding: 15px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}
input.selected_value {
    max-width: 50px;
}

button.cart__btns {
    background: black;
    color: white;
    border: black;
    border-radius: 3px;
    padding: 6px 10px;
    width: 48%;
}

.product_inner img {
    width: auto;
    height: 200px;
}

.greyed{
  background: #f4ffb8;
}
</style>


<div class="page-width">

<div class="stepfirst"> 
  <h2>STEP1:  Pick Bundle Quantity</h2>
  <div class="qty_selector_container">
    <button data-qty="2" class="button btn qty_for_bundle"> 2 </button>
    <button data-qty="3" class="button btn qty_for_bundle"> 3 </button>
    <button data-qty="4" class="button btn qty_for_bundle"> 4 </button>
    <button data-qty="5" class="button btn qty_for_bundle"> 5 </button>
  </div>
</div>

<br>
<br>
<br>
<h2>STEP2: Select Boards</h2>
<br>

<div class="product_wrapper">

  
{% for block in section.blocks %}
{% assign product = block.settings.product %}
{% assign img = product.featured_media %}
{% assign  title = product.title %}
{% assign  id = product.selected_or_first_available_variant.id %}
{% assign price = product.price | money_with_currency %}

<div class="product_inner">
<img src="{{ img | img_url: '180x' }}" width="" height="">
<div class="product_information_container">
<h3>{{ title }} </h3>
<p>{{price}}</p>
</div>
<div class="product_button"> 
<button id="addcart-{{ id }}" class="add-cart cart__btns btn" data-id="{{ id }}"> Add</button>
<input class="selected_value" value="" type="hidden">
<button id="removecart-{{ id }}" class="remove-cart cart__btns btn" data-id="{{ id }}"> Remove </button>
</div>
</div>

{% endfor %}
</div>

<br>
<br>
<br>
<h2>STEP3: Add to cart</h2>
<br>

<button class="button btn" id="addbundle"> Add Bundle </button>
</div>

<div class="progress_bar">  
    <div class="progress_bar_container">
        <div class="step-1 step_s"> Step-1: Pick bundle quantity <span class="done_svg"> ✓ </span>
      <span class="qty-info"></span>
      </div>
        <div class="step-2 step_s"> Step-2: Select Boards  <span class="done_svg"> ✓ </span></div>
        <div class="step-3 step_s"> Step-3: Add to cart or Create new bundle <span class="done_svg"> ✓ </span> </div>
    </div>
</div>

{% schema %}
{
  "name": "Custom add to cart",
  "tag": "section",
  "class": "Custom-add-to-cart",
  "settings": [
    
  ],
  "blocks": [
    {
      "type": "heading",
      "name": "Product",
      "settings": [
        {
      "type": "product",
      "id": "product",
      "label": "Select product"
    },
      ]
    },
  ],
  "presets": [
    {
      "name": "Custom add to cart"
    }
  ]
}
{% endschema %}


<script>

// ======================step1==========================
let limit;
const step1 = document.querySelector('.step-1');
const step2 = document.querySelector('.step-2');
const step3 = document.querySelector('.step-3');
const qtyinfo = document.querySelector('.qty-info');

var qtyselctory = document.querySelectorAll('.qty_for_bundle');
qtyselctory.forEach(select=>{
  select.addEventListener('click', function(){
    const selectedqty = select.getAttribute('data-qty');
limit = selectedqty;
{% comment %} myLimit(); {% endcomment %}
step1.classList.add('this_active');
qtyinfo.innerText = '(' + limit + 'Pack)';
  });
});

function myLimit() {
  alert(limit);
 
}

// ======================step2==========================

let dataArray = [];
var allButtons = document.querySelectorAll(".add-cart");
var removeButtons = document.querySelectorAll(".remove-cart");

allButtons.forEach(button => {
  button.addEventListener('click', function() {
    const getthisid = button.getAttribute('data-id');   
    {% comment %} alert(getthisid); {% endcomment %}
     
if (dataArray.length < limit){
   dataArray.push(getthisid);

  const thisparent = button.closest('.product_inner');
  thisparent.classList.add('greyed');

      {% comment %} myFunction(); {% endcomment %}
      if (dataArray.length == limit){
  step2.classList.add('this_active');
}
} 
else {
  alert('Limit reached!');
}

  });
});

function myFunction() {
  alert(dataArray);
 
}

removeButtons.forEach(removebtns => {
removebtns.addEventListener('click', function() {
const removethisid = removebtns.getAttribute('data-id');
{% comment %} alert(removethisid); {% endcomment %}
const index = dataArray.indexOf(removethisid);
dataArray.splice(index,1);

const thisparent = removebtns.closest('.product_inner');
  thisparent.classList.remove('greyed');

if (dataArray.length < limit){
  step2.classList.remove('this_active');
}
 {% comment %} myFunction(); {% endcomment %}

})
})

// ======================step3==========================

var carticon = document.querySelector('.cart-count-bubble');
var addbundle = document.getElementById('addbundle');
addbundle.addEventListener('click', function(){

let items = [];

    items.push(
      ...Array.from(dataArray).map(id => ({
        id: parseInt(id, 10),
        quantity: 1,
      }))
    );

    if (items.length > 0) {

      fetch("/cart/add.js", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ items })
      })
        .then(response => response.json())
        .then (data => {
          if (data.errors) {
          {% comment %} alert( "Products failed to the add"); {% endcomment %}

          } else {
            {% comment %} alert( "Products added to the cart successfully!"); {% endcomment %}
            
            step3.classList.add('this_active'); 
            {% comment %} setTimeout(mycarFunction, 1000);  {% endcomment %}
            updateCartBubble();

            updateCartDrawer();
            
            updateCartUI(); 
            openCartDrawer();

            setTimeout(removeclasses, 1000);
          }
        });


    } 
    function updateCartDrawer() {
      const drawerItems = document.querySelector('cart-drawer-items');
      if (drawerItems && typeof drawerItems.onCartUpdate === 'function') {
        drawerItems.onCartUpdate();
         
      } else {
        document.dispatchEvent(new Event('cart:updated')); 
      }
    }


    function updateCartUI() {
        document.dispatchEvent(new Event('cart:updated'));
    }

    function openCartDrawer() {
      document.querySelector('cart-drawer').classList.remove('is-empty');
       document.querySelector('cart-drawer').classList.add('active');
    } 

function updateCartBubble() {
  fetch(`${window.location.pathname}?sections=cart-icon-bubble`)
    .then(res => res.text())
    .then(text => {
      const data = JSON.parse(text);

      const html = data["cart-icon-bubble"];
      if (!html) return;

      // Create a temporary DOM parser to extract only the bubble
      const parser = new DOMParser();
      const doc = parser.parseFromString(html, "text/html");

      const newBubble = doc.querySelector(".cart-count-bubble");
      const currentBubble = document.querySelector("#cart-icon-bubble .cart-count-bubble");

      if (newBubble && currentBubble) {
        currentBubble.innerHTML = newBubble.innerHTML;
      }
    })
    .catch(err => console.error("Cart bubble update failed:", err));
}

function removeclasses() {
  const stepss = document.querySelectorAll('.step_s');
  const productinner = document.querySelectorAll('.product_inner');
  
  stepss.forEach(step=> {
     step.classList.remove('this_active'); 
  })

    productinner.forEach(pdct=> {
     pdct.classList.remove('greyed'); 
  })

  dataArray.length = 0;
     limit = 0;
     qtyinfo.innerText = '';
}

});


</script>

TRY THIS:

function updateCartBubble() {

fetch(`${window.location.pathname}?sections=cart-icon-bubble`)

.then((response) => response.json())

.then((sections) => {

const element = document.getElementById(‘cart-icon-bubble’);

if (element && sections[‘cart-icon-bubble’]) {

element.innerHTML = sections[‘cart-icon-bubble’];

}

});

}