Skip to content
Cart Upsell Checkbox (Add Gift Wrap Checkbox To Cart) - Free Tutorial
Browse other ways to boost conversion rate & profit

Cart Upsell Checkbox (Add Gift Wrap Checkbox To Cart) - Free Tutorial

Want personalized guidance adding this to your store?

Check out our Insiders community: https://www.skool.com/the-prompted

Members of The Prompted community receive a detailed store audit, 1-on-1 guidance for implementing new features, and access to an exclusive theme. You'll also get marketing support, the same tactics we use to spend over $100k/mo on Meta Ads.

---

In this tutorial, we're going to add a gift wrapping upsell to your cart.

There isn’t a great way to do this in the standard Shopify settings, so I’m going to show you how. And this is something you can do yourself without having to install an app or pay a developer.

Don’t worry if you’ve never done this before, I’ll take you through it step by step.

Compatible Themes: This code should work on all free Shopify themes (Dawn, Refresh, Craft, Studio, Publisher, Crave, Origin, Taste, Colorblock, Sense, Ride, Spotlight).

Edit Theme Code

Add settings to settings_schema.json

      {
        "type": "header",
        "content": "Cart Upsell"
      },
      {
        "type": "checkbox",
        "id": "enable_cart_upsell",
        "label": "Enable Cart Upsell Checkbox",
        "default": false
      },
      {
        "type": "product",
        "id": "cart_upsell_product",
        "label": "Cart Upsell Product",
        "info": "Note: Defaults to first variant of the selected product"
      },
      {
        "type": "text",
        "id": "cart_upsell_text",
        "label": "Cart Upsell Text",
        "default": "Add Gift Wrap"
      },
      {
        "type": "range",
        "id": "cart_upsell_font_size",
        "label": "Font Size",
        "min": 10,
        "max": 20,
        "default": 14
      },
      {
        "type": "select",
        "id": "cart_upsell_font_weight",
        "label": "Font Weight",
        "options": [
          {
            "value": "normal",
            "label": "Normal"
          },
          {
            "value": "600",
            "label": "Semi-Bold"
          },
          {
            "value": "bold",
            "label": "Bold"
          }
        ],
        "default": "normal"
      },
      {
        "type": "select",
        "id": "cart_upsell_alignment",
        "label": "Cart Upsell Alignment",
        "options": [
          {
            "value": "left",
            "label": "Left"
          },
          {
            "value": "right",
            "label": "Right"
          }
        ],
        "default": "right"
      }

Edit main-cart-footer.liquid

Add js asset

{% if settings.enable_cart_upsell %}
  {%- unless settings.cart_type == 'drawer' -%}
    <script src="{{ 'cart-checkbox-upsell.js' | asset_url }}" defer="defer"></script>
  {%- endunless -%}
{% endif %}

Add checkbox code

{% if settings.enable_cart_upsell %}
  {% render 'cart-checkbox-upsell' %}
{% endif %}

Edit cart-drawer.liquid

Add js asset

{% if settings.enable_cart_upsell %}
  <script src="{{ 'cart-checkbox-upsell.js' | asset_url }}" defer="defer"></script>
{% endif %}

Add checkbox code

{% if settings.enable_cart_upsell %}
  {% render 'cart-checkbox-upsell' %}
{% endif %}

Add new snippet cart-checkbox-upsell.liquid

{% assign upsell_product = all_products[settings.cart_upsell_product] %}
{% if upsell_product %}
  {% assign variant_id = upsell_product.variants.first.id %}
  <div class="cart-upsell" style="text-align: {{ settings.cart_upsell_alignment }}; font-size: {{ settings.cart_upsell_font_size }}px; font-weight: {{ settings.cart_upsell_font_weight }};">
    <label for="cart-upsell-checkbox" class="custom-checkbox">
      <input type="checkbox" id="cart-upsell-checkbox" class="custom-checkbox__input" name="cart-upsell" value="1" data-variant-id="{{ variant_id }}">
      <span class="custom-checkbox__icon"></span>
      {{ settings.cart_upsell_text }} 
    </label>
  </div>
{% endif %}

<style>

#main-cart-footer.is-empty .cart-upsell {
  display: none;
}

#cart-upsell-checkbox {
  display: none;
}

.custom-checkbox {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
}

.custom-checkbox__icon {
  width: 16px;
  height: 16px;
  border: 1px solid currentColor;
  margin-right: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: transparent;
}

.custom-checkbox__input:checked + .custom-checkbox__icon {
  background-color: rgb(var(--color-background));
}

.custom-checkbox__icon::before {
  content: '';
  width: 10px;
  height: 5px;
  border-left: 2px solid currentColor; 
  border-bottom: 2px solid currentColor;
  transform: translate(0, -1px) rotate(-45deg);
  opacity: 0; /* Hidden when unchecked */
}

.custom-checkbox__input:checked + .custom-checkbox__icon::before {
  opacity: 1; /* Show checkmark when checked */
}

</style>

Create a new asset cart-checkbox-upsell.js

class CartCheckboxUpsell {
  constructor(cartItemsInstance) {
    this.cartItemsInstance = cartItemsInstance;
    this.baseUrl = '/cart';
    this.checkboxUpsellVariantId = this.getUpsellCheckboxVariantId();
    this.initEventDelegation();
    document.addEventListener('cartUpdated', this.handleCartUpdate.bind(this));
    this.updateCheckboxState();
  }

  initEventDelegation() {
    document.body.addEventListener('change', (event) => {
      if (event.target.id === 'cart-upsell-checkbox') {
        const isChecked = event.target.checked;
        if (isChecked) {
          this.addUpsellCheckboxToCart();
        } else {
          this.removeUpsellCheckboxFromCart();
        }
      }
    });
  }

  getUpsellCheckboxVariantId() {
    return document.querySelector('#cart-upsell-checkbox')?.getAttribute('data-variant-id');
  }

  updateCheckboxState() {
    fetch(`${this.baseUrl}.js`)
      .then(response => response.json())
      .then(cart => {
        const hasUpsellCheckbox = cart.items.some(item => item.variant_id.toString() === this.checkboxUpsellVariantId);
        const checkboxUpsellCheckbox = document.querySelector('#cart-upsell-checkbox');
        if (checkboxUpsellCheckbox) {
          checkboxUpsellCheckbox.checked = hasUpsellCheckbox;
        }
      })
      .catch(error => {
        console.error('Error fetching cart:', error);
      });
  }

  handleCartUpdate() {
    setTimeout(() => this.updateCheckboxState(), 500); 
  }

  addUpsellCheckboxToCart() {
    const formData = new FormData();
    formData.append('id', this.checkboxUpsellVariantId);
    formData.append('quantity', 1);

    fetch(`${this.baseUrl}/add.js`, {
      method: 'POST',
      body: formData
    })
    .then(response => {
      if (response.ok) {
        if (this.cartItemsInstance && typeof this.cartItemsInstance.onCartUpdate === 'function') {
          this.cartItemsInstance.onCartUpdate();
          this.onCartUpdateCheckboxUpsell();
        }
      }
      return response.json();
    })
    .catch(error => {
      console.error('Error adding cart upsell:', error);
    });
  }

  removeUpsellCheckboxFromCart() {
    fetch('/cart.js')
      .then(response => response.json())
      .then(cart => {
        const lineItemIndex = cart.items.findIndex(item => item.variant_id.toString() === this.checkboxUpsellVariantId);
        if (lineItemIndex !== -1) {
          const line = lineItemIndex + 1;
          this.cartItemsInstance.updateQuantity(line, 0, null, null);
        } else {
          console.error('Cart upsell product not found in cart.');
        }
      })
      .catch(error => {
        console.error('Error fetching cart for cart upsell removal:', error);
      });
  }

getSectionsToRenderCheckboxUpsell() {
  const mainCartFooter = document.getElementById('main-cart-footer');
  const sections = [
    ...(mainCartFooter ? [{
      id: 'main-cart-footer',
      section: mainCartFooter.dataset.id,
      selector: '#main-cart-footer .js-contents',
    }] : []),
    {
      id: 'cart-icon-bubble',
      section: 'cart-icon-bubble',
      selector: '#cart-icon-bubble',
    },
  ];
  return sections;
}

  
  onCartUpdateCheckboxUpsell() {
    this.getSectionsToRenderCheckboxUpsell().forEach(section => {
      fetch(`${routes.cart_url}?section_id=${section.section}`)
        .then(response => response.text())
        .then(html => {
          const container = document.querySelector(section.selector);
          if (!container) {
            console.error(`Container not found for selector: ${section.selector}`);
            return;
          }
          if (section.id === 'main-cart-footer') {
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, "text/html");
            const jsContents = doc.querySelector('.js-contents');
  
            if (jsContents) {
              container.innerHTML = jsContents.innerHTML;
            } else {
              console.error(`.js-contents not found in fetched HTML for section: ${section.id}`);
            }
          } 
          else if (section.id === 'cart-icon-bubble') {
            container.innerHTML = html;
          }
        })
        .catch(error => console.error(`Error updating section ${section.id}:`, error));
    });
  }
  
}

document.addEventListener('DOMContentLoaded', function() {
    const cartItemsInstance = document.querySelector('cart-items');
    const cartDrawerItemsInstance = document.querySelector('cart-drawer-items');
    let activeCartInstance = cartDrawerItemsInstance || cartItemsInstance; 
    if (activeCartInstance) {
        new CartCheckboxUpsell(activeCartInstance);
    } else {
        console.log("Neither cart-items nor cart-drawer-items found in the DOM.");
    }
});

Add custom event to cart.js

const cartUpdatedEvent = new CustomEvent('cartUpdated', {
  detail: {
    message: 'Cart was updated',
  }
});
document.dispatchEvent(cartUpdatedEvent);
Browse other ways to boost conversion rate & profit