How to auto-add a required packaging item (like a gift box) to a BYOB bundle
This theme customization makes a required packaging item, like a gift box, add itself to a BYOB (Build Your Own Bundle) pack as soon as the page loads. Shoppers can't remove it. For setup steps on BYOB itself, see How to create a Build Your Own Bundle (BYOB) on Shopify.
What does it do?
The code looks for a required BYOB section that contains a single product. When the page loads, it adds that product to the pack and hides its quantity stepper and remove button. The product card shows "Included in every box" instead.
The packaging item takes one slot right away, so shoppers can only fill the rest of the pack from your other sections. That gives you a shared limit across those sections. For example, on a 7-item pack with one gift box, shoppers can pick any 6 toys and snacks in any mix, and the pack stops accepting items once it's full.
When should I use it?
Use it when every pack must include one packaging item and you want shoppers to spend their picks only on the products they're choosing. Two common cases:
- A gift box or assembly fee on a party favor box: 6 toys and snacks in any mix, plus the gift box added automatically.
- A required branded box or greeting card on a snack or coffee subscription box, so shoppers don't have to find and add it themselves.
Before you start
In your BYOB bundle, put the packaging product in its own section, with no other products in it, and set that section's quantity to exactly 1. Count it in the pack size, so a pack of 6 picks plus a gift box is a 7-item pack.
How do I set it up?
- From your Shopify admin, go to Online Store > Themes. Click ... on your live theme and choose Duplicate. Make these changes on the copy.
- On the copy, click ... > Edit code.
- In the Snippets folder, click Add a new snippet and name it byob-giftbox (the file will be snippets/byob-giftbox.liquid).
- Paste the code below into the new snippet.
- Replace
GIFT-BOX-SECTION-NAMEwith your packaging section's name, exactly as it's set in the app. Capital letters, spaces and symbols must all match. - Optional: change the
Included in every boxlabel in the code to your own wording. - Click Save.
- Open layout/theme.liquid and paste this line just before the closing
</body>tag, then save:
{% if template.name == 'product' %}{% render 'byob-giftbox' %}{% endif %}
The snippet code:
<!-- Start Simple Bundles edits -->
{% comment %}
Auto-adds the product in a required single-product BYOB section (e.g. a gift box)
and hides its remove option. Because it takes 1 slot as soon as the page loads,
the remaining slots can only be filled from the other sections.
Safe to load on every product page: it does nothing if the section isn't there.
{% endcomment %}
<script>
(function () {
var SECTION = 'GIFT-BOX-SECTION-NAME'; // must match the section name in the app exactly
var MAX_ATTEMPTS = 5;
var attempts = 0;
var queued = false;
// Hide the gift box quantity stepper and its Remove button, show "Included" instead
var css = ''
+ '.byob-bundle__product-section[aria-label="' + SECTION + '"] .byob-stepper{display:none!important}'
+ '.byob-bundle__product-section[aria-label="' + SECTION + '"] .byob-bundle__product-card:has(.byob-stepper) .byob-bundle__product-card-meta::after{'
+ 'content:"Included in every box";display:block;margin-top:8px;font-size:12px;font-weight:600;opacity:.75}'
+ '.byob-mini-cart .byob-resource[aria-label="' + SECTION + '"] .byob-resource__remove{display:none!important}';
var style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
function giftSection() {
return document.querySelector('.byob-bundle__product-section[aria-label="' + SECTION + '"]');
}
function ensureGiftBoxAdded() {
queued = false;
var section = giftSection();
if (!section || attempts >= MAX_ATTEMPTS) return;
// Already in the box: the card shows a stepper instead of the Add button
if (section.querySelector('.byob-stepper')) return;
// Out of stock or box already full: leave it alone
var addBtn = section.querySelector('button.byob-cta--add:not([disabled])');
if (!addBtn) return;
attempts++;
addBtn.click();
// Fallback in case the card opens its modal instead of adding straight away
setTimeout(function () {
var dialog = section.querySelector('dialog.byob-options-modal[open]');
if (!dialog) return;
var modalAdd = dialog.querySelector('button.byob-cta--full:not([disabled])');
if (modalAdd) modalAdd.click();
if (dialog.open) dialog.close();
}, 300);
}
function schedule() {
if (queued) return;
queued = true;
requestAnimationFrame(ensureGiftBoxAdded);
}
// The widget renders after page load, so watch for it (and re-add if it ever gets removed)
new MutationObserver(schedule).observe(document.documentElement, { childList: true, subtree: true });
schedule();
})();
</script>
<!-- END Simple Bundles edits -->
What are the limits?
- The section name in the code must match the app exactly. On translated storefronts the section name is shown in the shopper's language, so it won't match and the item won't be added there.
- It only works when the packaging section has one product. If you list several box options in that section, the code won't pick one for the shopper.
- If the packaging product is out of stock, it isn't added, and shoppers can't complete the pack until it's back in stock.
How do I test it?
Always test on the theme copy first. Use Preview on the copy, open your BYOB product, and check that the packaging item is already in the pack, that it can't be removed, and that the pack fills up and adds to cart as expected. Once it looks right, publish the copy.
If anything doesn't work as expected, or you'd like us to set it up for you, reach out to our support team and we'll help.