3-Steps to Better Quantity Selectors on Your Shopify Theme

In Technical Brief by Alex Ortiz

There are a few options when it comes to e-commerce quantity selectors, but an interactive element seems to be the most user-friendly for B2C retail sites. 

A good “interactive” quantity selector typically means that the user doesn’t need to pull up a menu or use their keyboard, they can just tap or click right on the screen. Cool, right?

So what if your Shopify theme just has the default HTML input field? Maybe you’ve got something that looks a bit like this (an extremely small touch area for mobile devices)… 

But you’re a smart cookie that’s aiming for something more intuitive (and aesthetically pleasing), like this…

Just one problem: your Shopify theme has an AJAX cart and you have no idea how to add functionality for dynamically loaded elements.

This walkthrough will show you how to completely integrate new quantity selector buttons and improve your default Shopify store. Mobile1st was just implementing this change for a client using the Streamline theme, and we thought it would be helpful to share these steps with you! Afterall, sharing is caring. 

Note: You’ll need to have basic knowledge of HTML & CSS; and an understanding of how javascript works to trigger a quantity change when a user clicks on your new buttons.


I recommend making a copy of your live theme before editing any code. Changing a live theme can be very risky if you’re not entirely sure what you’re doing and/or making bigger changes (like this one) that span multiple files. Working in a duplicate theme will allow you to verify and test your changes in preview mode before going live. 

STEP 1: Add buttons to the quantity selector

To set this up, you’ll go into the cart template or cart-drawer template and search for “quantity” to find the input element responsible for updating the quantity of a given line item. 

We’re then going to add a button above and below the quantity input; these will be used to increase/decrease the value.

<button type=’button’ value=’-‘ class=’qtyminus’> – </button>
<input type=”number” name=”updates[]” id=”cart_updates_{{ item.key }}” class=”cart__quantity” value=”{{ item.quantity }}” min=”0″ data-id=”{{ item.key }}” data-cart-item-input-quantity>
<button type=’button’ value=’+’ class=’qtyplus’> + </button>

The input field was left as is, but you’ll want to pay attention to the button’s classes. For this tutorial, I’ve chosen the classes qtyminus and qtyplus which will be used again later in the Javascript to determine how the quantity should be changed. 

From here, you could add in a bit of Javascript to change the quantity on click (in most cases). But if your cart uses AJAX to dynamically change the contents of the cart each time it’s updated – you’ll see that your trigger only works on initial page load. 

This is because the AJAX is only updating the page content, and not reinitializing your event handler. So your fancy new buttons are being destroyed and reloaded, but your event handler isn’t being reattached.

STEP 2: Tell your new buttons what to do

This is where it gets fun (or messy… I’m not here to judge). 

Locate a file called theme.js and search for something like “cart” or “AjaxCart” to find the cart’s constructor. If you’re editing the Streamline theme, this is called “theme.AjaxCart”.

STEP 2a: Define those variables

Look for the handler’s variable object, most commonly named “selectors”. This is where you’ll define your “+” and “-” buttons. It will look something like this.

    var selectors = {
      form: ‘form.cart’,
      cartCount: ‘.cart-link__count’,
      updateBtn: ‘.update-cart’,
      itemList: ‘[data-cart-item-list]’,
      item: ‘[data-cart-item]’,
      itemId: ‘[data-cart-item-id]’,
      itemHref: ‘[data-cart-item-href]’,
      itemBackgroundImage: ‘[data-cart-item-background-image]’,
      itemTitle: ‘[data-cart-item-title]’,
      itemVariantTitle: ‘[data-cart-item-variant-title]’,
      itemPropertyList: ‘[data-cart-item-property-list]’,
      itemProperty: ‘[data-cart-item-property]’,
      itemDiscountList: ‘[data-cart-item-discount-list]’,
      itemDiscount: ‘[data-cart-item-discount]’,
      itemDiscountTitle: ‘[data-cart-item-discount-title]’,
      itemDiscountAmount: ‘[data-cart-item-discount-amount]’,
      itemLabelQuantity: ‘[data-cart-item-label-quantity]’,
      itemInputQuantity: ‘[data-cart-item-input-quantity]’,

      itemDelete: ‘[data-cart-item-delete]’,
      itemPriceContainer: ‘[data-cart-item-price-container]’,
      itemLinePriceContainer: ‘[data-cart-item-line-price-container]’,
      itemUnitPrice: ‘[data-cart-item-unit-price]’,
      itemMessage: ‘[data-item-message]’,
      itemSubscriptionName: ‘[data-cart-item-subscription-name]’,
      cartDiscountContainer: ‘[data-cart-discount-container]’,
      cartDiscountContent: ‘[data-cart-discount-content]’,
      cartDiscount: ‘[data-cart-discount]’,
      cartDiscountTitle: ‘[data-cart-discount-title]’,
      cartDiscountAmount: ‘[data-cart-discount-amount]’,
      cartNoteContainer: ‘[data-cart-note-container]’,
      cartNoteInput: ‘[data-cart-note]’,
      cartMessage: ‘[data-cart-message]’,
      cartSubtotal: ‘[data-cart-subtotal]’,
      cartSubmit: ‘[data-cart-submit]’

Highlighted in orange are the lines I’ve added. *Depending on what class you’ve given your new buttons, this may look slightly different. 

STEP 2b: Add event listeners

Further down, there should be a prototype function where the event listeners are being defined. We’ll be making quite a few updates here. In orange are the lines I’ve added to listen for clicks on both of the buttons, and in blue is what I swapped from ‘input’ to ‘change’.

    this.$container.on(‘click’, selectors.itemInputMinus, this._updateQuantity);
        this.$container.on(‘click’, selectors.itemInputPlus, this._updateQuantity);
        this.$container.on(‘click’, selectors.itemDelete, this._onItemDelete.bind(this));
        this.$container.on(‘change‘, selectors.itemInput Quantity, $.debounce
(500, this._onItemQuantityChange.bind(this)));
        this.$container.on(‘blur’, selectors.itemInputQuantity, this._onItemQuantityEmptyBlur.bind(this));
        this.$container.on(‘focus’, selectors.itemInputQuantity, this._highlightText);

STEP 2c: Turn button clicks into quantity updates

Locate the function called  “_onItemQuantityChange”, and place this next function just above it (to keep things organized). 

      _updateQuantity: function(evt){
        var $button = $(evt.target).closest(‘button’);
        var $input = $button.parent().find(‘input[type=”number”]’);
        var id = $input.closest(selectors.item).attr(data.itemId);
        var quantity = $input.val();
        if ($button.hasClass(‘qtyplus’)) {
              quantity = parseInt($input.val()) + 1;
        } else {
          quantity = parseInt($input.val()) – 1;
        if (quantity == 0) {
          var response = confirm(theme.strings.cartConfirmDelete);
          if (response === false) {
        theme.cart.changeItem(id, quantity);

This function takes the event that just occurred (ie. the button click) and determines whether or not it should increase or decrease the input value. Once the new quantity has been calculated, the function calls “changeItem” – which has already been defined in the theme’s javascript – to trigger the AJAX update on the cart. 

And because we’ve added this to the cart’s constructor, this code will continue to work every time the content is loaded. 

STEP 3: Test your code and make it mini 

This is going to get wordy, so bear with me. Comment out everything in theme.min.js and paste all of the contents from theme.js (temporarily) – just to avoid minifying code that doesn’t actually work. Once you’ve verified that your code is running as intended, head over to a Javascript minifier site and paste the code you just copied. This will give you a minified version of the theme.js file. Minified javascript dramatically improves site speed and accessibility (aka – a better user experience). Now you’ll go back to theme.min.js, remove the unminified content, and paste in your new minified theme code. 

Et voilà! You now have a user-friendly, aesthetically pleasing quantity selector that’s completely integrated into your Shopify theme. No duct tape required.

If this tutorial was a bit out of your depth, or you often find yourself in need of this kind of Shopify-related development, we’re here to help! Mobile1st is key for clients just like you; the ultimate optimization partner that will continuously improve your conversion rates. Just sit back and let our team of certified Shopify Experts give you the high-converting theme of your dreams.

Mobile1st is a leader in marketing technology and site optimization solutions. More than prioritizing and executing industry leading CRO practices, we do what makes the money; optimizing our Client’s digital commerce product toward consistent financial growth and ROI. All achieved through excellence in Lean UX, Analytics, Research, Experimentation and Development.
Contact Mobile1st Experts Now!

Alex Ortiz
Latest posts by Alex Ortiz (see all)