For developers

Optional hooks for developers of apps that sell kits or bundles of a product, such as “buy 3 and save”, from an app block on the product page. The theme needs none of this to work: without such a block, these events never fire and the page works as described in Product pages.

Before you edit code: duplicate the theme first and work on the copy (see Duplicate the theme). The hooks below are described so that your app can use them; writing or debugging code that uses them is a customization and is not covered by theme support. If you need help with custom code, we suggest hiring a Shopify Partner.

kit:change

Dispatch a CustomEvent named kit:change on document every time the shopper changes the kit in your block. The theme’s product page (the Product information section) listens to it.

document.dispatchEvent(new CustomEvent('kit:change', {
  detail: {
    productId: 1234567890,     // the product of the page
    quantity: 3,               // units in the kit; 1 = back to one unit
    percent: 15,               // the kit's discount, in percent
    unitPrice: 2125,           // price per unit in the kit, in cents
    compareAtUnit: 2500,       // full price per unit, in cents
    total: 6375,               // price of the kit, in cents
    compareAtTotal: 7500,      // full price of the kit, in cents
    saving: 1125,              // total saving, in cents
    formatted: {               // the same amounts, formatted with the shop's money format
      unit: '$21.25',
      compareAtUnit: '$25.00',
      total: '$63.75',
      compareAtTotal: '$75.00',
      saving: '$11.25'
    },
    activeIndex: 0,            // the kit item being chosen (0 = the first); -1 with one unit
    variantId: 9876543210,     // the variant chosen for that item, or null
    complete: false            // whether every item of the kit has a variant
  }
}));

What the theme does with it:

The theme never formats money: it writes the formatted strings as they come, and an event without them changes nothing. The words come from the theme’s translations, so merchants can change them in Edit default theme content. The price block keeps the line in a live region, so screen readers announce the kit when it changes.

kit:added

After your block has added the kit to the cart, dispatch a cancelable kit:added event on document:

const event = new CustomEvent('kit:added', {
  cancelable: true,
  detail: {
    productId: 1234567890,
    quantity: 3,
    instance: 'kit-1',                         // your own id for this kit
    items: [{ id: 9876543210, quantity: 3 }]   // the variants added to the cart
  }
});
document.dispatchEvent(event);
if (!event.defaultPrevented) {
  window.location.href = `${window.Shopify?.routes?.root ?? '/'}cart`;
}

When the merchant uses the cart drawer (Theme settings › Cart › Cart type set to Drawer), the theme cancels the event, opens the drawer and redraws it, so the shopper stays on the page. When the event is not cancelled, the cart drawer isn’t in use, and your block can send the shopper to the cart page as in the example.

html[data-kit-active]

While the shopper builds a kit in your block, set the data-kit-active attribute on the <html> element, and remove it when they go back to buying one unit:

document.documentElement.toggleAttribute('data-kit-active', quantity > 1);

With the attribute present, the theme hides the Variant picker and Buy buttons blocks of the product page, since your block brings its own, so the page never shows two add buttons. On phones, the page also stops keeping room for the theme’s buy bar at the bottom of the screen.