Skip to content

Configuration Attributes

Configuration attributes control formatting, behavior, and appearance without writing JavaScript.

Control how values are displayed and formatted.

Specify how numeric values should be formatted.

<!-- Currency formatting (default for prices) -->
<span data-next-display="cart.total"
data-format="currency">
$99.99
</span>
<!-- Number only (no currency symbol) -->
<span data-next-display="cart.total"
data-format="number">
99.99
</span>
<!-- Integer (no decimals) -->
<span data-next-display="cart.totalQuantity"
data-format="integer">
5
</span>
<!-- Percentage -->
<span data-next-display="package.123.discountPercent"
data-format="percentage">
30%
</span>
<!-- Custom decimal places -->
<span data-next-display="cart.tax"
data-format="currency"
data-decimal-places="3">
$8.999
</span>
FormatDescriptionExample Output
currencyWith currency symbol$99.99
numberNumeric only99.99
integerNo decimals100
percentagePercentage format30%
autoAuto-detect formatVaries

Hide decimal places when value has no cents.

<!-- Shows $100 instead of $100.00 -->
<span data-next-display="package.123.price"
data-format="currency"
data-hide-zero-cents="true">
$100
</span>
<!-- Shows $99.99 (cents visible) -->
<span data-next-display="package.456.price"
data-format="currency"
data-hide-zero-cents="true">
$99.99
</span>

Hide element completely when value is zero.

<!-- Hidden when no discount -->
<div data-next-display="cart.discount"
data-hide-if-zero="true">
<span>Discount: </span>
<span data-next-display="cart.discount">$0.00</span>
</div>
<!-- Hidden when no shipping cost -->
<div data-next-display="cart.shipping"
data-hide-if-zero="true">
Shipping: <span>$0.00</span>
</div>

Hide element when boolean value is false.

<div data-next-display="cart.hasDiscount"
data-hide-if-false="true">
Discount applied!
</div>
<div data-next-display="package.123.inStock"
data-hide-if-false="true">
In stock and ready to ship
</div>

Perform calculations on displayed values.

Multiply the value before displaying.

<!-- Convert cents to dollars -->
<span data-next-display="package.123.priceInCents"
data-divide-by="100"
data-format="currency">
$9.99
</span>
<!-- Show annual price from monthly -->
<span data-next-display="package.123.monthlyPrice"
data-multiply-by="12"
data-format="currency">
$1,188/year
</span>
<!-- Calculate percentage -->
<span data-next-display="cart.discount"
data-divide-by="cart.subtotal"
data-multiply-by="100"
data-format="percentage">
10%
</span>

Divide the value before displaying.

<!-- Show price per item -->
<span data-next-display="cart.total"
data-divide-by="cart.totalQuantity"
data-format="currency">
$19.99/item
</span>
<!-- Convert to percentage -->
<span data-next-display="package.123.savings"
data-divide-by="package.123.originalPrice"
data-multiply-by="100"
data-format="percentage">
30% off
</span>

Add a value to the displayed number.

<!-- Show price with tax -->
<span data-next-display="package.123.price"
data-add="package.123.tax"
data-format="currency">
$109.99
</span>

Subtract from the displayed value.

<!-- Calculate savings -->
<span data-next-display="package.123.originalPrice"
data-subtract="package.123.price"
data-format="currency">
Save $20.00
</span>
<!-- Amount needed for free shipping -->
<span data-next-display="100"
data-subtract="cart.total"
data-format="currency"
data-hide-if-zero="true">
$25.00 away from free shipping
</span>

Configure countdown timers and urgency elements.

<!-- Basic timer (5 minutes) -->
<div data-next-timer="true"
data-duration="300">
05:00
</div>
<!-- Timer with custom format -->
<div data-next-timer="true"
data-duration="3600"
data-format="hh:mm:ss">
01:00:00
</div>
<!-- Timer with persistence -->
<div data-next-timer="true"
data-duration="86400"
data-persistence-id="sale-timer"
data-format="dd:hh:mm:ss">
1d 00:00:00
</div>
<!-- Timer with expiry action -->
<div data-next-timer="true"
data-duration="600"
data-on-expire="hide"
data-expire-message="Offer expired">
10:00
</div>
AttributePurposeValues
data-durationTimer duration in secondsNumber
data-formatDisplay formatmm:ss, hh:mm:ss, dd:hh:mm:ss, auto
data-persistence-idPersist across refreshesString ID
data-on-expireAction when timer endshide, show-message, redirect
data-expire-messageMessage to showString
data-expire-urlURL to redirect toURL

Configure package selector behavior.

<!-- Swap mode - immediate cart update -->
<div data-next-package-selector="true"
data-next-selection-mode="swap">
<button data-next-package-id="123">Option A</button>
<button data-next-package-id="456">Option B</button>
</div>
<!-- Select mode - requires add button -->
<div data-next-package-selector="true"
data-next-selection-mode="select">
<label>
<input type="radio" name="package" data-next-package-id="123">
Option A
</label>
<label>
<input type="radio" name="package" data-next-package-id="456">
Option B
</label>
<button data-next-action="add-selected">Add to Cart</button>
</div>
<!-- Multi-select mode -->
<div data-next-package-selector="true"
data-next-selection-mode="multi"
data-max-selections="3">
<label>
<input type="checkbox" data-next-package-id="123">
Add-on A
</label>
<label>
<input type="checkbox" data-next-package-id="456">
Add-on B
</label>
<label>
<input type="checkbox" data-next-package-id="789">
Add-on C
</label>
</div>
ModeDescriptionUse Case
swapImmediate cart replacementSingle product selection
selectSelection then actionComplex product configuration
multiMultiple selectionsAdd-ons and bundles

Configure loading behavior during actions.

<!-- Custom loading text -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-loading-text="Processing..."
data-loading-class="is-busy">
Add to Cart
</button>
<!-- Don't disable during loading -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-disable-on-loading="false">
Add to Cart
</button>
<!-- Custom spinner -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-loading-spinner="true"
data-spinner-class="custom-spinner">
Add to Cart
</button>

Configure how actions behave.

Prevent rapid repeated actions.

<!-- 500ms debounce (default 300ms) -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-debounce="500">
Add to Cart
</button>
<!-- No debounce -->
<button data-next-quantity="increase"
data-next-package-id="123"
data-debounce="0">
+
</button>

Update UI immediately while action processes.

<!-- Optimistic UI updates -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-optimistic="true">
Add to Cart
</button>
<!-- Pessimistic (wait for server) -->
<button data-next-action="checkout"
data-optimistic="false">
Checkout
</button>
<!-- Custom success message -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-success-message="Item added!"
data-success-class="show-success">
Add to Cart
</button>
<!-- Custom error handling -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-error-message="Could not add item"
data-error-class="show-error">
Add to Cart
</button>
<!-- Redirect on success -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-success-url="/cart">
Add to Cart
</button>

Configure profile-based behavior.

<!-- Profile switcher with options -->
<button data-next-profile="premium"
data-next-clear-cart="true"
data-next-preserve-quantities="false">
Switch to Premium
</button>
<!-- Profile selector dropdown -->
<select data-next-profile-selector="true"
data-next-clear-cart="false">
<option value="">Regular</option>
<option value="premium">Premium Member</option>
<option value="vip">VIP</option>
</select>
<!-- Profile-specific text -->
<button data-next-profile="vip"
data-active-text="VIP Active"
data-inactive-text="Activate VIP">
Activate VIP
</button>

Configure quantity controls and limits.

<!-- Quantity with custom step -->
<button data-next-quantity="increase"
data-next-package-id="123"
data-step="5">
+5
</button>
<!-- Quantity with limits -->
<input type="number"
data-next-quantity="input"
data-next-package-id="123"
min="1"
max="10"
step="1"
data-enforce-limits="true">
<!-- Quantity sync with package -->
<div data-next-quantity-sync="123">
<button data-next-quantity="decrease">-</button>
<span data-next-display="package.123.quantity">1</span>
<button data-next-quantity="increase">+</button>
</div>

Configure upsell behavior and display.

<!-- Direct upsell with timer -->
<div data-next-upsell="offer"
data-next-package-id="123"
data-timer="30"
data-auto-skip="true">
<h3>Special Offer!</h3>
<button data-next-upsell-action="add">Yes, Add This</button>
<button data-next-upsell-action="skip">No Thanks</button>
</div>
<!-- Quantity upsell -->
<div data-next-upsell="quantity"
data-next-package-id="123"
data-suggested-quantity="3">
<button data-next-upsell-quantity="decrease">-</button>
<span data-next-upsell-quantity="display">1</span>
<button data-next-upsell-quantity="increase">+</button>
</div>
<!-- Selection upsell -->
<div data-next-upsell-selector="true"
data-required="true">
<label>
<input type="radio" data-next-upsell-option="456">
Upgrade to Premium
</label>
<label>
<input type="radio" data-next-upsell-option="789">
Upgrade to Ultimate
</label>
</div>

Page-level configuration via meta tags.

<head>
<!-- API configuration -->
<meta name="next-api-key" content="your-api-key">
<meta name="next-debug" content="true">
<!-- Page type -->
<meta name="next-page-type" content="product">
<!-- Navigation control -->
<meta name="next-prevent-back-navigation" content="true">
<!-- Upsell configuration -->
<meta name="next-upsell-accept-url" content="/success">
<meta name="next-upsell-decline-url" content="/cart">
<!-- Timer configuration -->
<meta name="next-timer-duration" content="600">
<meta name="next-timer-persistence" content="session">
</head>
<div class="product-card">
<!-- Dynamic price with formatting -->
<span data-next-display="package.123.price"
data-format="currency"
data-hide-zero-cents="true">
$99
</span>
<!-- Conditional discount display -->
<div data-next-show="package.123.hasDiscount">
<s data-next-display="package.123.originalPrice"
data-format="currency">$129</s>
<span data-next-display="package.123.discountPercent"
data-format="percentage">23% off</span>
</div>
<!-- Configured action button -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-loading-text="Adding..."
data-success-message="Added!"
data-optimistic="true"
data-debounce="300">
Add to Cart
</button>
</div>
<div class="checkout-container">
<!-- Minimum order amount -->
<div data-next-show="cart.total < 25">
<span>Add $</span>
<span data-next-display="25"
data-subtract="cart.total"
data-format="number">0</span>
<span> more for checkout</span>
</div>
<!-- Checkout button with validation -->
<button data-next-action="checkout"
data-next-show="cart.total >= 25"
data-loading-text="Processing..."
data-optimistic="false"
data-validate="true">
Proceed to Checkout
</button>
</div>

General utility attributes for common scenarios.

<!-- Uppercase text -->
<span data-next-display="package.123.name"
data-text-transform="uppercase">
PRODUCT NAME
</span>
<!-- Lowercase text -->
<span data-next-display="cart.customer.email"
data-text-transform="lowercase">
</span>
<!-- Title case -->
<span data-next-display="package.123.category"
data-text-transform="title">
Product Category
</span>
<!-- Sentence case -->
<span data-next-display="package.123.description"
data-text-transform="sentence">
Product description here.
</span>
<!-- Truncate text -->
<p data-next-display="package.123.description"
data-truncate="150"
data-truncate-suffix="...">
Long description text will be cut off at 150 characters...
</p>
<!-- Extract first word -->
<span data-next-display="cart.customer.name"
data-extract="first-word">
John
</span>
<!-- Extract last word -->
<span data-next-display="cart.customer.name"
data-extract="last-word">
Smith
</span>
<!-- Extract initials -->
<span data-next-display="cart.customer.name"
data-extract="initials">
J.S.
</span>
<!-- Replace text -->
<span data-next-display="package.123.status"
data-replace="in_stock:In Stock,out_of_stock:Out of Stock">
In Stock
</span>
<!-- Format date -->
<span data-next-display="order.createdAt"
data-date-format="MM/dd/yyyy">
12/25/2023
</span>
<!-- Relative time -->
<span data-next-display="order.createdAt"
data-date-format="relative">
2 hours ago
</span>
<!-- Time only -->
<span data-next-display="order.createdAt"
data-date-format="HH:mm">
14:30
</span>
<!-- Add days to date -->
<span data-next-display="order.createdAt"
data-add-days="7"
data-date-format="MM/dd/yyyy">
01/01/2024
</span>
<!-- Countdown to date -->
<span data-next-countdown="order.estimatedDelivery"
data-format="dd:hh:mm:ss">
3d 12:45:30
</span>
<!-- Convert text to URL -->
<a data-next-display="package.123.name"
data-url-base="/products/"
data-url-transform="slug"
href="/products/awesome-product">
Awesome Product
</a>
<!-- Generate share URL -->
<a data-next-share="facebook"
data-share-url="window.location.href"
data-share-title="package.123.name"
href="https://facebook.com/sharer/...">
Share on Facebook
</a>
<!-- Email link -->
<a data-next-display="cart.customer.email"
data-link-type="email"
data-email-subject="Your Order Confirmation"
href="mailto:[email protected]?subject=Your Order Confirmation">
</a>
<!-- Phone link -->
<a data-next-display="cart.customer.phone"
data-link-type="tel"
href="tel:+1234567890">
(123) 456-7890
</a>
<!-- Dynamic classes based on values -->
<div data-next-display="package.123.stock"
data-class-map="0:out-of-stock,1-5:low-stock,6+:in-stock"
class="in-stock">
Stock Level: <span>10</span>
</div>
<!-- Toggle classes -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-toggle-class="added"
data-toggle-duration="2000">
Add to Cart
</button>
<!-- Conditional classes -->
<div data-next-show="cart.hasItems"
data-show-class="has-items"
data-hide-class="empty-cart">
Cart content
</div>
<!-- Progress classes -->
<div data-next-display="cart.total"
data-progress-target="100"
data-progress-class="progress-{percentage}">
<!-- Adds class like "progress-75" for 75% progress -->
</div>
<!-- Fade in on change -->
<span data-next-display="cart.total"
data-animate="fade"
data-animation-duration="300">
$99.99
</span>
<!-- Slide animation -->
<div data-next-show="cart.hasItems"
data-animate="slide"
data-slide-direction="down">
Cart items
</div>
<!-- Count up animation -->
<span data-next-display="cart.count"
data-animate="count-up"
data-count-duration="500">
5
</span>
<!-- Pulse on change -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-animate="pulse"
data-trigger="success">
Add to Cart
</button>
<!-- Input validation -->
<input type="email"
data-next-validate="email"
data-validate-message="Please enter a valid email"
data-validate-class="invalid">
<!-- Real-time formatting -->
<input type="tel"
data-format-input="phone"
data-format-pattern="(000) 000-0000"
placeholder="(123) 456-7890">
<!-- Auto-complete -->
<input type="text"
data-next-autocomplete="cart.customer.cities"
data-autocomplete-limit="5">
<!-- Input masking -->
<input type="text"
data-input-mask="0000-0000-0000-0000"
data-mask-placeholder="_"
placeholder="0000-0000-0000-0000">
<!-- Lazy load image -->
<img data-next-display="package.123.image"
data-lazy="true"
data-lazy-threshold="100"
data-lazy-placeholder="/placeholder.jpg"
alt="Product image">
<!-- Preload critical data -->
<div data-preload="cart,packages"
data-preload-priority="high">
Critical content
</div>
<!-- Debounced input -->
<input type="search"
data-next-search="packages"
data-debounce="300"
data-min-length="3">
<!-- Virtual scrolling -->
<div data-next-cart-items
data-virtual-scroll="true"
data-item-height="80"
data-buffer-size="5">
</div>
<!-- Screen reader only text -->
<span data-next-display="cart.count"
data-screen-reader-text="items in cart">
5 <span class="sr-only">items in cart</span>
</span>
<!-- ARIA attributes -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-aria-label="Add {package.123.name} to cart"
data-aria-describedby="product-description">
Add to Cart
</button>
<!-- Live region announcements -->
<div data-next-display="cart.count"
data-announce-changes="true"
data-announcement-text="{value} items in cart">
5
</div>
<!-- Focus management -->
<button data-next-action="add-to-cart"
data-next-package-id="123"
data-focus-target="#cart-summary"
data-focus-delay="500">
Add to Cart
</button>
<!-- Remember user preferences -->
<select data-next-remember="currency-preference"
data-storage="localStorage">
<option value="USD">USD</option>
<option value="EUR">EUR</option>
</select>
<!-- Session storage -->
<input type="text"
data-next-remember="search-query"
data-storage="sessionStorage"
data-remember-key="last-search">
<!-- Clear storage -->
<button data-next-action="clear-storage"
data-storage-keys="cart-data,user-preferences">
Reset All Data
</button>
<!-- Debug information -->
<div data-debug="true"
data-debug-show="cart"
data-debug-format="json">
<!-- Shows cart data in debug mode -->
</div>
<!-- Performance monitoring -->
<div data-monitor="render-time"
data-monitor-threshold="100"
data-monitor-alert="console">
Content to monitor
</div>
<!-- Feature flags -->
<div data-feature-flag="new-checkout"
data-fallback="hide">
New checkout flow content
</div>
<!-- A/B testing -->
<div data-ab-test="checkout-flow"
data-variant="a"
data-probability="50">
Variant A content
</div>
<form data-next-multi-step="true"
data-step-validation="true"
data-save-progress="true">
<!-- Step 1 -->
<div data-step="1"
data-step-title="Contact Information"
data-next-show="form.currentStep === 1">
<input type="email"
name="email"
data-validate="email"
required>
<button data-next-step="next"
data-validate-current="true">
Next
</button>
</div>
<!-- Step 2 -->
<div data-step="2"
data-step-title="Shipping Address"
data-next-show="form.currentStep === 2">
<input type="text"
name="address"
data-validate="required"
data-autocomplete="address">
<button data-next-step="previous">Back</button>
<button data-next-step="next">Next</button>
</div>
<!-- Step 3 -->
<div data-step="3"
data-step-title="Review & Submit"
data-next-show="form.currentStep === 3">
<button data-next-action="checkout"
data-validate-all="true">
Complete Order
</button>
</div>
</form>
<div class="pricing-calculator">
<!-- Base price -->
<div data-next-display="package.123.basePrice"
data-format="currency"
data-id="base-price">
$99.99
</div>
<!-- Add-ons -->
<div data-calculate="true"
data-base="base-price"
data-add="selected-addons"
data-format="currency">
$129.99
</div>
<!-- Quantity discount -->
<div data-quantity-discount="true"
data-breaks="5:0.1,10:0.15,20:0.2"
data-apply-to="calculated-total">
Bulk discount applied
</div>
<!-- Final total -->
<div data-next-display="calculated-total"
data-add="shipping"
data-add="tax"
data-format="currency"
data-animate="count-up">
$156.78
</div>
</div>
<div data-recommendations="true"
data-based-on="cart.items"
data-algorithm="collaborative"
data-limit="4"
data-exclude="cart.packageIds">
<template data-recommendation-template>
<div class="recommendation-item">
<img data-src="{item.image}"
data-lazy="true"
alt="{item.name}">
<h4>{item.name}</h4>
<span data-format="currency">{item.price}</span>
<button data-next-action="add-to-cart"
data-next-package-id="{item.id}"
data-track="recommendation-click">
Add to Cart
</button>
</div>
</template>
</div>