Gift Wrap Checkbox

A paid gift wrap add-on with an optional gift message, right above add to cart.

One section file Product page, directly under the buy buttons Edit in the theme editor

Important: Before making any changes to your theme, duplicate it in Online Store > Themes so you have a backup.

Gift wrap is one of the easiest add-ons to sell: it costs little to fulfil and shoppers already expect to pay for it. This section adds a checkbox to your product page. When it's ticked, a gift wrap product is added to the cart and the gift message is saved on the order.

Preview

What you'll build

Add to cart
Add a gift message (optional)

Preview with the default settings. Colours, text and layout can all be changed in the theme editor.

Install

Add it to your store in 4 steps

  1. 1

    Open your theme code

    In Shopify admin go to Online Store > Themes. Next to the theme you want to edit, click the three dots and choose Edit code.

  2. 2

    Create the section

    In the Sections folder click Add a new section, name it lt-gift-wrap-checkbox, delete the placeholder code, paste in the code below and click Save.

  3. 3

    Add it in the theme editor

    Click Customize, go to Products > Default product, click Add section and choose Gift wrap checkbox.

  4. 4

    Make it yours

    Change the settings in the sidebar, drag the section where you want it, and click Save.

sections/lt-gift-wrap-checkbox.liquid · 210 lines
{%- comment -%}
  Gift wrap / add-on checkbox by LAUNCHTIP
  https://launchtip.com/free-shopify-sections-code
{%- endcomment -%}
{%- liquid
  assign wrap = section.settings.wrap_product
  assign wrap_variant = wrap.selected_or_first_available_variant
  assign wrap_price = wrap_variant.price | money
-%}

{%- if wrap != blank and wrap_variant.available -%}
  {%- style -%}
    #lt-{{ section.id }} { padding: {{ section.settings.padding }}px 0; }
    #lt-{{ section.id }} .lt-gw { display: flex; gap: 12px; align-items: flex-start; border: 1px solid {{ section.settings.border_color }}; border-radius: 8px; padding: 14px 16px; cursor: pointer; background: {{ section.settings.background }}; }
    #lt-{{ section.id }} .lt-gw input[type="checkbox"] { width: 18px; height: 18px; margin-top: 2px; accent-color: {{ section.settings.accent }}; flex-shrink: 0; }
    #lt-{{ section.id }} .lt-gw img { width: 48px; height: 48px; object-fit: cover; border-radius: 6px; flex-shrink: 0; }
    #lt-{{ section.id }} .lt-gw__title { font-weight: 600; display: block; }
    #lt-{{ section.id }} .lt-gw__text { font-size: 0.9em; opacity: 0.8; }
    #lt-{{ section.id }} .lt-gw__message { display: none; width: 100%; margin-top: 10px; padding: 10px; border: 1px solid {{ section.settings.border_color }}; border-radius: 6px; font: inherit; resize: vertical; }
    #lt-{{ section.id }}.is-checked .lt-gw__message { display: block; }
  {%- endstyle -%}

  <div
    id="lt-{{ section.id }}"
    class="page-width"
    data-variant-id="{{ wrap_variant.id }}"
    data-cart-url="{{ routes.cart_url }}"
    data-property="{{ section.settings.property_name | escape }}"
  >
    <label class="lt-gw">
      <input type="checkbox" class="lt-gw__check">
      {%- if section.settings.show_image and wrap.featured_image != blank -%}
        {{ wrap.featured_image | image_url: width: 120 | image_tag: loading: 'lazy', alt: wrap.title }}
      {%- endif -%}
      <span>
        <span class="lt-gw__title">{{ section.settings.heading | replace: '[price]', wrap_price }}</span>
        <span class="lt-gw__text">{{ section.settings.text | replace: '[price]', wrap_price }}</span>
      </span>
    </label>
    {%- if section.settings.show_message -%}
      <textarea
        class="lt-gw__message"
        rows="2"
        maxlength="200"
        placeholder="{{ section.settings.message_placeholder | escape }}"
        aria-label="{{ section.settings.message_placeholder | escape }}"
      ></textarea>
    {%- endif -%}
  </div>

  <script>
    (function () {
      var root = document.getElementById('lt-{{ section.id }}');
      if (!root || root.dataset.ready) return;
      root.dataset.ready = '1';

      var checkbox = root.querySelector('.lt-gw__check');
      var message = root.querySelector('.lt-gw__message');
      var variantId = Number(root.dataset.variantId);
      var property = root.dataset.property;

      function productForm() {
        return document.querySelector('main form[action*="/cart/add"]') ||
          document.querySelector('form[action*="/cart/add"]');
      }

      function setProperty(form, name, value) {
        var input = form.querySelector('input[data-lt-gift="' + name + '"]');
        if (!value) { if (input) input.remove(); return; }
        if (!input) {
          input = document.createElement('input');
          input.type = 'hidden';
          input.name = 'properties[' + name + ']';
          input.dataset.ltGift = name;
          form.appendChild(input);
        }
        input.value = value;
      }

      function sync() {
        var form = productForm();
        root.classList.toggle('is-checked', checkbox.checked);
        if (!form) return;
        setProperty(form, property, checkbox.checked ? 'Yes' : '');
        setProperty(form, 'Gift message', checkbox.checked && message ? message.value.trim() : '');
      }

      function addWrapToCart() {
        return fetch(root.dataset.cartUrl + '.js', { headers: { Accept: 'application/json' } })
          .then(function (r) { return r.json(); })
          .then(function (cart) {
            var already = cart.items.some(function (item) { return item.variant_id === variantId; });
            if (already) return;
            return fetch(window.Shopify && Shopify.routes ? Shopify.routes.root + 'cart/add.js' : '/cart/add.js', {
              method: 'POST',
              keepalive: true,
              headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
              body: JSON.stringify({ items: [{ id: variantId, quantity: 1 }] })
            });
          })
          .then(function () {
            document.dispatchEvent(new CustomEvent('cart:refresh', { bubbles: true }));
          })
          .catch(function () {});
      }

      checkbox.addEventListener('change', sync);
      if (message) message.addEventListener('input', sync);

      var form = productForm();
      if (form) {
        form.addEventListener('submit', function () {
          sync();
          if (checkbox.checked) addWrapToCart();
        }, true);
      }
    })();
  </script>
{%- elsif request.design_mode -%}
  <div class="page-width" style="padding: 20px 0;">
    <p style="padding: 14px; border: 1px dashed #999; border-radius: 8px;">Gift wrap: pick your gift wrap product in the section settings.</p>
  </div>
{%- endif -%}

{% schema %}
{
  "name": "Gift wrap checkbox",
  "tag": "section",
  "class": "lt-gift-wrap-section",
  "settings": [
    {
      "type": "product",
      "id": "wrap_product",
      "label": "Gift wrap product",
      "info": "Create a product called Gift wrap with the price you want to charge, then pick it here."
    },
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Add gift wrap for [price]",
      "info": "[price] is replaced with the gift wrap price."
    },
    {
      "type": "text",
      "id": "text",
      "label": "Text",
      "default": "Wrapped by hand with a handwritten note."
    },
    {
      "type": "checkbox",
      "id": "show_image",
      "label": "Show gift wrap image",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "show_message",
      "label": "Show gift message box",
      "default": true
    },
    {
      "type": "text",
      "id": "message_placeholder",
      "label": "Gift message placeholder",
      "default": "Add a gift message (optional)"
    },
    {
      "type": "text",
      "id": "property_name",
      "label": "Line item label",
      "default": "Gift wrap",
      "info": "Shown on the order next to the product being wrapped."
    },
    {
      "type": "color",
      "id": "accent",
      "label": "Checkbox colour",
      "default": "#111111"
    },
    {
      "type": "color",
      "id": "border_color",
      "label": "Border colour",
      "default": "#e5e5e5"
    },
    {
      "type": "color",
      "id": "background",
      "label": "Background",
      "default": "#ffffff"
    },
    {
      "type": "range",
      "id": "padding",
      "label": "Vertical padding",
      "min": 0,
      "max": 60,
      "step": 4,
      "unit": "px",
      "default": 12
    }
  ],
  "presets": [
    {
      "name": "Gift wrap checkbox"
    }
  ]
}
{% endschema %}
Customization

What you can change in the theme editor

Setting Default
Gift wrap product Create a product called Gift wrap with the price you want to charge, then pick it here. —
Heading [price] is replaced with the gift wrap price. Add gift wrap for [price]
Text Wrapped by hand with a handwritten note.
Show gift wrap image On
Show gift message box On
Gift message placeholder Add a gift message (optional)
Line item label Shown on the order next to the product being wrapped. Gift wrap
Checkbox colour #111111
Border colour #e5e5e5
Background #ffffff
Vertical padding 12px
Good to know

Tips for setting it up

  • Create a product called Gift wrap first, set its price, and untick Track quantity so it never sells out.
  • Leave the gift wrap product out of every collection so shoppers don't come across it while browsing.
  • The gift message is saved as a line item property on the main product, so it appears on the order and packing slip.
  • Only one gift wrap is added per order, even if the shopper adds several products with the box ticked.

Further reading: Best product add-ons apps for Shopify

FAQ

Frequently asked questions

Does this work with the cart drawer?

The gift wrap is added in the background when the shopper presses add to cart. Most themes show it the next time the cart opens. If your drawer opens before it's added, refresh the drawer or turn on the cart page in your theme settings.

Can I charge per item instead of per order?

Yes. Remove the check for an existing gift wrap line in the script and it will add one gift wrap for every add to cart.

Will the gift message show on my packing slip?

Line item properties show on the order page in Shopify admin. Most packing slip templates include them; if yours doesn't, add line_item.properties to the template in Settings > Shipping and delivery > Packing slip template.

SellUp

Want this without the code?

SellUp shows checkbox add-ons like gift wrap and warranties on any product, styled to match your theme, and adds them in the same click as the main item. No theme code to test or maintain.

Try SellUp

More free sections

New

Frequently Bought Together

Hand-picked product bundles with checkboxes, a running total and one add-all button.

New

Free Shipping Progress Bar

"You're £12 away from free shipping" with a bar that fills as the cart grows.

New

Quantity Price-Break Table

Buy 2 save 10%, buy 3 save 15%: a tiered pricing table with the price each worked out.

Explore More Free Sections

Discover more code snippets to enhance your Shopify store.

View All Sections
SellUp Increase AOV with Upsells