Next Commerce
Cart System

Package Toggle

The Package Toggle lets visitors independently add or remove individual packages — add-ons, insurance, warranties, upgrades, or any optional item. Unlike the Package Selector (pick one), any number of toggles can be active at the same time.

How It Works

  1. Add data-next-package-toggle to a container and place [data-next-toggle-card] children with data-next-package-id
  2. Clicking a card that is not in the cart adds it; clicking one that is in the cart removes it
  3. Mark a card data-next-selected="true" to auto-add it on page load (deduped across page refreshes)
  4. Backend prices are fetched in full cart context so offer conditions (e.g. "spend $100 get 20% off") are reflected

Activation

<div data-next-package-toggle>
  <!-- toggle cards go here -->
</div>

Container Attributes

AttributeValuesDescription
data-next-package-toggleMarks the container (or the toggle element itself in single-element mode)
data-next-include-shippingtrue | falseInclude shipping in price totals shown via data-next-toggle-price
data-next-packagesJSON arrayPackage definitions for auto-render mode (see below)
data-next-toggle-template-idelement IDID of a <template> element whose innerHTML is the card template
data-next-toggle-templateHTML stringInline card template alternative to data-next-toggle-template-id

Card Attributes

AttributeDescription
data-next-toggle-cardMarks an element as a toggleable card
data-next-package-idPackage ref_id (required per card)
data-next-selected="true"Auto-adds this package on page load
data-next-quantityQuantity to add (default 1)
data-next-package-syncComma-separated list of package IDs — quantity mirrors the sum of those packages in the cart
data-next-is-upsell="true"Marks the item as an upsell/bump for order tracking
data-add-textButton text shown when package is not in the cart
data-remove-textButton text shown when package is in the cart

Displaying Package Images

Add data-next-toggle-image to any <img> inside a card. The enhancer sets its src (and alt, if blank) from the campaign package data automatically.

<div data-next-toggle-card data-next-package-id="201">
  <img data-next-toggle-image alt="Warranty" />
  <span>2-Year Warranty</span>
</div>

Displaying Backend Prices

Place [data-next-toggle-price] inside a card or its template. Prices are calculated with the full current cart as context so offer discounts that depend on cart total are correctly reflected.

<span data-next-toggle-price></span>                    <!-- total (default) -->
<span data-next-toggle-price="subtotal"></span>
<span data-next-toggle-price="compare"></span>          <!-- compare-at / retail price -->
<span data-next-toggle-price="savings"></span>
<span data-next-toggle-price="savingsPercentage"></span>

Prices for in-cart items are read directly from the cart summary (no extra API call). Prices for not-in-cart items are fetched via /calculate with the item simulated in the cart. A next-loading class and data-next-loading="true" are set on the card during fetches.

CSS Classes

ClassApplied toWhen
next-toggle-cardEach registered cardAlways (on registration)
next-in-cartA cardThe package is in the cart
next-not-in-cartA cardThe package is not in the cart
next-selectedA cardAlias for next-in-cart
next-activeA cardAlias for next-in-cart
next-loadingA cardDuring an async cart operation

The same classes are also set on the card's nearest state container (see State Containers).

Events

EventPayloadWhen
toggle:toggled{ packageId, added }A card is clicked
toggle:selection-changed{ selected: number[] }Cart sync updates the active set

Basic Example

<div data-next-package-toggle>

  <div data-next-toggle-card
       data-next-package-id="201"
       data-add-text="Add Warranty"
       data-remove-text="✓ Warranty Added">
    2-Year Warranty
    <span data-next-toggle-price></span>
  </div>

  <div data-next-toggle-card
       data-next-package-id="202"
       data-next-selected="true"
       data-add-text="Add Insurance"
       data-remove-text="✓ Insurance Added">
    Shipping Insurance
    <span data-next-toggle-price></span>
    <del data-next-toggle-price="compare"></del>
  </div>

</div>

Single-Element Toggle

Place data-next-package-toggle directly on a button or any single element when no card container is needed.

<button data-next-package-toggle
        data-next-package-id="201"
        data-add-text="Add Warranty — $9.99"
        data-remove-text="✓ Warranty Added">
  Add Warranty — $9.99
</button>

The element acts as both the container and the card. All state classes (next-in-cart, next-not-in-cart, etc.) are applied directly to it. In single-element mode, the element's textContent is replaced directly with the add/remove text. In card mode, add a [data-next-button-text] child element to scope the text update:

<div data-next-toggle-card
     data-next-package-id="201"
     data-add-text="Add Warranty"
     data-remove-text="✓ Added">
  <img data-next-toggle-image />
  <span data-next-button-text>Add Warranty</span>
</div>

Auto-Render Mode

Provide a JSON array via data-next-packages and a card template via data-next-toggle-template-id. The enhancer renders one card per definition, enriching template variables with campaign package data.

Package Definition Format

[
  { "packageId": 201, "label": "2-Year Warranty" },
  { "packageId": 202, "label": "Shipping Insurance", "selected": true }
]

Set "selected": true to auto-add that package on load. Any field is available as {toggle.<fieldName>} in the template.

Template Variables

VariableSourceDescription
{toggle.packageId}JSON / campaignPackage ref_id
{toggle.name}Campaign storePackage name
{toggle.image}Campaign storePackage image URL
{toggle.price}Campaign storePer-unit price
{toggle.priceRetail}Campaign storeRetail/compare-at price
{toggle.priceRetailTotal}Campaign storeRetail total price
{toggle.<anyField>}JSONAny other field from the definition

Example

<div data-next-package-toggle
     data-next-packages='[
       {"packageId":201,"label":"2-Year Warranty"},
       {"packageId":202,"label":"Shipping Insurance","selected":true}
     ]'
     data-next-toggle-template-id="toggle-tpl">
</div>

<template id="toggle-tpl">
  <div data-next-toggle-card
       data-add-text="Add {toggle.label}"
       data-remove-text="✓ {toggle.label} Added">
    <strong>{toggle.label}</strong>
    <span data-next-toggle-price></span>
    <del data-next-toggle-price="compare"></del>
  </div>
</template>

Quantity Sync

Use data-next-package-sync when the add-on quantity should automatically mirror the main product quantity — for example one warranty unit per product unit.

<!-- Main product selector (packages 10, 11, 12 represent 1-, 3-, and 6-bottle options) -->
<div data-next-package-selector data-next-selector-id="qty-picker">
  <div data-next-selector-card data-next-package-id="10" data-next-selected="true">1 Bottle</div>
  <div data-next-selector-card data-next-package-id="11">3 Bottles</div>
  <div data-next-selector-card data-next-package-id="12">6 Bottles</div>
</div>

<!-- Warranty auto-syncs its quantity to match packages 10, 11, or 12 in the cart -->
<div data-next-package-toggle>
  <div data-next-toggle-card
       data-next-package-id="201"
       data-next-package-sync="10,11,12">
    Add Warranty (quantity matches your order)
    <span data-next-toggle-price></span>
  </div>
</div>

data-next-package-sync accepts a comma-separated list of package IDs. The toggle card's quantity is set to the sum of quantities of those packages currently in the cart. When all synced packages are removed, the toggle item is automatically removed too.


State Containers

The enhancer walks up the DOM from each card looking for a wrapper element that should receive state classes. This lets you style an outer container rather than the card itself.

State container detection checks these attributes/classes in order:

  • data-next-toggle-container
  • data-next-bump
  • data-next-upsell-item
  • .upsell or .bump CSS classes

If none is found, the card element itself is the state container. The following attributes and classes are applied to the state container:

data-in-cart="true|false"
data-next-active="true|false"
.next-in-cart  /  .next-not-in-cart
.next-active

Listening to Toggle Events

window.nextReady.push(() => {
  window.next.on('toggle:toggled', ({ packageId, added }) => {
    console.log(added ? 'Added:' : 'Removed:', packageId);
  });

  window.next.on('toggle:selection-changed', ({ selected }) => {
    console.log('Active packages:', selected);
  });
});

On this page