Slot Templates
Add data-next-bundle-slot-template-id to the container and place a [data-next-bundle-slots] placeholder inside each card to render one row per bundle item with variant selectors.
<div data-next-bundle-selector
data-next-bundle-slot-template-id="slot-tpl">
<div data-next-bundle-card
data-next-bundle-id="duo"
data-next-bundle-items='[{"packageId":10,"quantity":1},{"packageId":20,"quantity":1}]'>
<h3>Duo Bundle</h3>
<div data-next-bundle-slots></div>
<p>Total: <span data-next-bundle-display="price"></span></p>
</div>
</div>
<template id="slot-tpl">
<div class="slot-row">
<img src="{item.image}" alt="{item.name}" />
<strong>{item.name}</strong>
<span>{item.price}</span>
</div>
</template>Slot Template Variables
Slot position:
| Variable | Description |
|---|---|
{slot.index} | 1-based slot number |
{slot.unitNumber} | 1-based unit index within a configurable item |
{slot.unitIndex} | 0-based unit index within a configurable item |
Package identity:
| Variable | Description |
|---|---|
{item.packageId} | Package ID |
{item.name} | Package name |
{item.image} | Package image URL |
{item.quantity} | Quantity for this slot (number of units added to cart) |
{item.variantName} | Variant display name (e.g. "Black / Small") |
{item.productName} | Product name |
{item.sku} | Product SKU |
{item.isRecurring} | "true" / "false" |
Prices:
All values are pre-formatted currency strings (e.g. $10.00). {item.price} is the per-slot total — for a slot with quantity: 3, it is three times the unit price. Use {item.unitPrice} for the single-unit price. Currency is determined by the code returned from the bundle price fetch API; before the first fetch, the campaign's active currency is used.
| Variable | Description |
|---|---|
{item.price} | Slot price after discounts |
{item.originalPrice} | Slot price before discounts |
{item.unitPrice} | Single-unit price after discounts |
{item.originalUnitPrice} | Single-unit price before discounts |
{item.discountAmount} | Slot discount amount |
{item.discountPercentage} | Discount percentage (e.g. 20.00%) |
{item.recurringPrice} | Recurring slot price |
{item.originalRecurringPrice} | Recurring slot price before discounts |
{item.interval} | Billing interval — "day", "week", "month", or "" for one-time |
{item.intervalCount} | Intervals between billing cycles (e.g. 3), or "" for one-time |
{item.frequency} | Human-readable billing frequency (e.g. "Every 3 months", "One time") |
Conditional helpers:
| Variable | Values | Description |
|---|---|---|
{item.hasDiscount} | show / hide | Whether a discount is applied to this item |
{item.isRecurring} | true / false | Whether the item has recurring billing |
{item.currency} | ISO 4217 code | Currency code for this slot's prices (e.g. USD) |
Conditional Display in Slots
Use data-next-show and data-next-hide on elements inside a slot template to toggle visibility based on slot variables.
data-next-show="item.hasDiscount"— visible when the item has a discount, hidden otherwisedata-next-hide="item.isRecurring"— hidden when the item is recurring, visible otherwise
Truthy values: "show", "true", or any non-empty string that is not "hide" or "false".
<template id="slot-tpl">
<div class="slot-row">
<img src="{item.image}" alt="{item.name}" />
<strong>{item.name}</strong>
<span>{item.price}</span>
<div data-next-show="item.hasDiscount">
Save {item.discountPercentage}!
<del>{item.originalPrice}</del>
</div>
<div data-next-show="item.isRecurring">
Billed {item.frequency} — {item.recurringPrice}
</div>
<div data-next-hide="item.isRecurring">
One-time purchase
</div>
</div>
</template>Any data-next-show / data-next-hide value that matches a slot variable (e.g. item.*, slot.*) is evaluated locally at render time. Store-based conditions like data-next-show="cart.itemCount > 0" still work inside slot templates — they are handled by the global ConditionalDisplayEnhancer after the slot enters the DOM.
Per-Slot Discount List
Place a data-next-discounts container inside the slot template to render discounts applied to each individual package in the bundle.
<template id="slot-tpl">
<div class="slot-row">
<img src="{item.image}" alt="{item.name}" />
<strong>{item.name}</strong>
<span>{item.price}</span>
<div data-next-discounts>
<template>
<span class="badge">{discount.name}: -{discount.amount}</span>
</template>
</div>
</div>
</template>Discount row tokens
| Token | Description |
|---|---|
{discount.name} | Discount or offer name |
{discount.amount} | Formatted discount amount (e.g. "$10.00") |
{discount.description} | Human-readable description; empty when absent |
State classes
| Class | When |
|---|---|
next-discounts-empty | No discounts for this slot |
next-discounts-has-items | One or more discounts |
Per-slot discounts come from the per-line breakdown in the bundle price calculation. They are populated after each price fetch and cleared when the bundle is deselected.
The offer/voucher filter (data-next-discounts="offer" / ="voucher") is not available at slot level — per-line discounts from the API are not split by type. Use the unfiltered data-next-discounts attribute.
External Slot Rendering
Use data-next-bundle-slots-for on an element outside the selector container to receive the slot rows for the currently selected bundle. The value must match data-next-selector-id on the container.
<div data-next-bundle-selector data-next-selector-id="my-selector" ...>
<!-- bundle cards -->
</div>
<!-- Slots rendered here, outside the selector -->
<div data-next-bundle-slots-for="my-selector"></div>Per-Unit Configuration (Configurable Items)
By default, a quantity-3 item renders as a single slot. Add "configurable": true to expand it into individual per-unit slots — one per unit — each with its own variant selectors.
[
{
"id": "pick3",
"name": "Pick Your 3",
"items": [
{ "packageId": 101, "quantity": 3, "configurable": true }
]
}
]This renders three slot rows, each with independent variant dropdowns. The cart is updated with the aggregated package quantities after all selections.
Collecting Properties in Slot Templates
Add data-next-property to any <input>, <textarea>, or <select> inside a slot template to capture per-slot metadata and attach it to the corresponding line item in the cart.
<template id="slot-tpl">
<div class="slot-row">
<img src="{item.image}" alt="{item.name}" />
<strong>{item.name}</strong>
<span>{item.price}</span>
<!-- Each unit carries its own engraving text as a line item property -->
<input type="text"
data-next-property="engraving"
placeholder="Add personalisation text" />
</div>
</template>The value syncs to slot.properties on every input event. When the bundle is in swap mode, blurring the field immediately updates the cart — no extra submit step required. User-typed values survive slot re-renders caused by variant changes.
Page-Level Default Properties
For properties that apply to every slot across all bundles (e.g. a single gift message), use data-next-default-property anywhere on the page instead:
<!-- Applies to every line item from every bundle selector on the page -->
<textarea data-next-default-property="gift_message"
placeholder="Gift message (optional)"></textarea>
<div data-next-bundle-selector ...>
<!-- bundle cards -->
</div>Per-slot data-next-property values override page-level defaults when both share the same key.
Merge priority (highest wins): slot-level data-next-property → page-level data-next-default-property.
Unique Line Items by Properties
When two slots in a bundle share the same package_id but carry different property values (for example, two shirts with different engraving text), the cart treats them as separate line items rather than merging them. The cart summary also renders a separate row per unique property set automatically — no extra configuration needed.
Excluding Properties from a Slot
Use data-next-exclude-property on a slot template to prevent specific property keys from being sent to the order API for that line, without removing the inputs from the page.
| Value | Effect |
|---|---|
"team" | Excludes the team key from this slot |
"team, number" | Excludes multiple keys (comma-separated) |
"*" | Excludes all properties from this slot |
Set it in the bundle item JSON via excludeProperties:
// data-next-bundle-items JSON
{ "packageId": 123, "quantity": 1, "excludeProperties": "team, number" }When "*" is set, property listeners are not attached to the slot at all. For specific-key exclusions, values are collected live but filtered out at send time.
Silent Add-Ons (noSlot)
Set "noSlot": true on any bundle item to suppress its slot row. Useful for free gifts or invisible add-ons you want to include in the cart but not show in the slot list.
{
"id": "premium",
"items": [
{ "packageId": 10, "quantity": 1 },
{ "packageId": 99, "quantity": 1, "noSlot": true }
]
}