Cart Summary
The Cart Summary displays the cart totals — subtotal, discounts, shipping, and grand total — and updates automatically whenever the cart changes. Drop it anywhere on the page: a sidebar, a sticky footer, or an order review step.
What You're Building
- A live price breakdown that re-renders when items are added, removed, or discounts change
- Optional custom layout with your own markup
- Conditional rows that appear only when relevant (e.g. a discount row only when a coupon is active)
- An itemised line list with per-item pricing
Step 1: Minimal Setup
One attribute is all you need. The enhancer renders a built-in Subtotal / Discounts / Shipping / Total layout:
<div data-next-cart-summary></div>The built-in template only shows the discount row when discounts are greater than zero. No extra configuration needed.
Step 2: Custom Template
Place a <template> inside the container to replace the default layout with your own markup. Use {variable} placeholders for dynamic values.
<div data-next-cart-summary>
<template>
<div class="summary-row">
<span>Subtotal</span>
<span>{subtotal}</span>
</div>
<div class="summary-row discount-row">
<span>Discounts</span>
<span>−{totalDiscount}</span>
</div>
<div class="summary-row">
<span>Shipping</span>
<span>{shipping}</span>
</div>
<div class="summary-row total-row">
<span>Total</span>
<span>{total}</span>
</div>
</template>
</div>Available Template Variables
| Variable | Description |
|---|---|
{subtotal} | Subtotal before shipping and discounts |
{total} | Grand total |
{shipping} | Shipping cost (formatted, or "Free" when zero) |
{shippingOriginal} | Original shipping before any shipping discount (empty if none) |
{shippingDiscountAmount} | Absolute amount saved on shipping |
{shippingDiscountPercentage} | Shipping discount as a percentage (e.g. "10%") |
{shippingName} | Display name of the selected shipping method |
{shippingCode} | Code of the selected shipping method |
{totalDiscount} | Total discount amount (offers + vouchers combined) |
{totalDiscountPercentage} | Total discount as a percentage of subtotal (e.g. "20%") |
{discounts} | Deprecated alias for {totalDiscount} — still rendered |
{currency} | Active currency code (e.g. "USD") |
{itemCount} | Number of distinct lines in the cart |
{totalQuantity} | Total unit quantity across all lines |
{isEmpty} | "true" or "false" |
{hasDiscounts} | "true" or "false" |
{isFreeShipping} | "true" or "false" |
{hasShippingDiscount} | "true" or "false" |
{isCalculating} | "true" or "false" |
Step 3: Conditional Rows with CSS Classes
The enhancer applies state classes to the container element. Use them to show or hide rows with CSS instead of writing JavaScript.
<div data-next-cart-summary>
<template>
<div class="row"><span>Subtotal</span><span>{subtotal}</span></div>
<div class="row row-discounts"><span>Discounts</span><span>−{totalDiscount}</span></div>
<div class="row row-shipping-discount">
<span>Shipping</span>
<del>{shippingOriginal}</del>
<span>{shipping}</span>
</div>
<div class="row row-shipping-free"><span>Shipping</span><span>Free</span></div>
<div class="row row-total"><span>Total</span><span>{total}</span></div>
</template>
</div>
<style>
/* Hide these rows by default */
.row-discounts,
.row-shipping-discount { display: none }
/* Show when state classes are present */
.next-has-discounts .row-discounts { display: flex }
.next-has-shipping-discount .row-shipping-discount { display: flex }
.next-has-shipping .row-shipping-free { display: none }
.next-free-shipping .row-shipping-free { display: flex }
</style>State Classes Reference
| Class | When applied |
|---|---|
next-cart-empty | Cart has no items |
next-cart-has-items | Cart has one or more items |
next-has-discounts | Discount amount > 0 |
next-no-discounts | Discount amount = 0 |
next-has-shipping | Shipping cost > 0 |
next-free-shipping | Shipping cost = 0 |
next-has-shipping-discount | A shipping discount is applied |
next-no-shipping-discount | No shipping discount |
next-calculating | Totals recalculation is in progress |
next-not-calculating | Totals are up to date |
Step 4: Itemised Line List
Show a breakdown of each cart line — useful for an order review section. Add a [data-summary-lines] container inside your template with a <template> child for the row markup.
<div data-next-cart-summary>
<template>
<ul class="line-items" data-summary-lines>
<template>
<li class="line-item">
<img src="{item.image}" alt="{item.name}" />
<div class="line-info">
<strong>{item.name}</strong>
<span>{item.variantName}</span>
</div>
<div class="line-pricing">
<span>{item.quantity} × {item.unitPrice}</span>
<strong>{item.price}</strong>
</div>
</li>
</template>
</ul>
<div class="summary-row"><span>Subtotal</span><span>{subtotal}</span></div>
<div class="summary-row"><span>Shipping</span><span>{shipping}</span></div>
<div class="summary-row total-row"><span>Total</span><span>{total}</span></div>
</template>
</div>Line Item Variables
Use the {item.*} token namespace inside data-summary-lines row templates.
| Variable | Description |
|---|---|
{item.packageId} | Package ref_id |
{item.name} | Package display name |
{item.image} | Product image URL |
{item.productName} | Product name |
{item.variantName} | Variant name (e.g. "Black / Large") |
{item.sku} | Product SKU |
{item.quantity} | Quantity in cart |
{item.unitPrice} | Unit price after discounts |
{item.originalUnitPrice} | Unit price before discounts |
{item.price} | Package price after discounts |
{item.originalPrice} | Package price before discounts |
{item.discountAmount} | Total discount on this line |
{item.discountPercentage} | Discount as a percentage of original unit price |
{item.hasDiscount} | "show" or "hide" — useful as a CSS class |
{item.isRecurring} | "true" or "false" |
{item.interval} | Billing interval ("day", "month", or empty) |
{item.intervalCount} | Number of intervals per cycle |
{item.frequency} | Human-readable frequency (e.g. "Monthly") |
{item.recurringPrice} | Recurring unit price (subscriptions) |
{item.currency} | Currency code for this line |
The legacy
{line.*}token set is deprecated — those tokens render as empty strings and emit a console warning. Always use{item.*}in new templates.
Step 5: Discount Breakdowns
Show applied offer discounts and coupon codes as separate line items. Add list containers inside your template:
<div data-next-cart-summary>
<template>
<div class="row"><span>Subtotal</span><span>{subtotal}</span></div>
<!-- Offer discounts (e.g. "Buy 2 get 10% off") -->
<ul data-summary-offer-discounts>
<template>
<li class="discount-item">
<span>{discount.name}</span>
<span>−{discount.amount}</span>
</li>
</template>
</ul>
<!-- Applied coupon codes -->
<ul data-summary-voucher-discounts>
<template>
<li class="discount-item coupon">
<span>{discount.name}</span>
<span>−{discount.amount}</span>
</li>
</template>
</ul>
<div class="row"><span>Shipping</span><span>{shipping}</span></div>
<div class="row total-row"><span>Total</span><span>{total}</span></div>
</template>
</div>Discount item variables: {discount.name}, {discount.amount}, {discount.description}.
Full Example
A complete order review summary with line items, discount list, and conditional shipping row:
<div class="order-summary" data-next-cart-summary>
<template>
<h3>Order Summary</h3>
<p class="item-count">{itemCount} item(s)</p>
<ul class="line-items" data-summary-lines>
<template>
<li class="line-item">
<img src="{item.image}" alt="{item.name}" />
<div class="line-info">
<strong>{item.name}</strong>
<span class="variant">{item.variantName}</span>
</div>
<div class="line-price">
<span>{item.quantity} × {item.unitPrice}</span>
<strong>{item.price}</strong>
</div>
</li>
</template>
</ul>
<div class="divider"></div>
<div class="summary-row"><span>Subtotal</span><span>{subtotal}</span></div>
<ul class="discounts" data-summary-offer-discounts>
<template>
<li><span class="discount-name">{discount.name}</span><span>−{discount.amount}</span></li>
</template>
</ul>
<ul class="discounts" data-summary-voucher-discounts>
<template>
<li><span class="coupon-name">{discount.name}</span><span>−{discount.amount}</span></li>
</template>
</ul>
<div class="summary-row shipping-row">
<span>Shipping</span>
<span>{shipping}</span>
</div>
<div class="divider"></div>
<div class="summary-row discount-row">
<span>You save ({totalDiscountPercentage})</span>
<span class="discount-amount">−{totalDiscount}</span>
</div>
<div class="summary-row total-row">
<span>Total</span>
<strong>{total}</strong>
</div>
</template>
</div>
<style>
.order-summary {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 10px;
padding: 1.5rem;
}
.line-items { list-style: none; padding: 0; margin: 0 0 1rem }
.line-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.5rem 0;
}
.line-item img { width: 48px; height: 48px; object-fit: cover; border-radius: 4px }
.line-info { flex: 1 }
.variant { color: #6b7280; font-size: 0.85rem }
.summary-row {
display: flex;
justify-content: space-between;
padding: 0.35rem 0;
}
.total-row { font-size: 1.1rem; font-weight: 700 }
.divider { border-top: 1px solid #e5e7eb; margin: 0.75rem 0 }
.discounts { list-style: none; padding: 0; color: #16a34a }
.discounts li { display: flex; justify-content: space-between }
/* Hide discount row when no discount is applied */
.next-no-discounts .discount-row { display: none }
.discount-amount { color: #16a34a }
</style>