Skip to main content
A web component is the <dkl-price> tag written directly into your theme’s Liquid. On a product page it needs zero attributes — it clones a pre-staged carrier and renders the primary product’s price server-side.

Usage

On a product page, add the <dkl-price> web component — it renders the primary product’s price server-side:
<dkl-price></dkl-price>

Pairing with the volume picker

To let <dkl-price> own the price display, set the volume picker’s price target to none (data-price-target="none") and hide the theme’s native price. The picker then only emits tier-change events, and <dkl-price> is the single element that updates.

Beta Limitation for Web Components: Single Product Context

During beta of the DKL Live Components, a web component is only recommended for product pages / where the products shown on the page are static on page load.For use on a page where new product instances are loaded in via the Section Rendering API / Ajax (such as a paginated collection page for example) we recommend using the app block instead. See App blocks vs. Web Components.

Reacting to changes

<dkl-price> emits a discount-kit-live:price:change event whenever its displayed price updates — the recommended hook for running your own code when the price moves. It carries the previous and new price (see the Events reference). See Listen for price changes below. Two narrower alternatives:
  • Listen for the tier event — the volume picker’s discount-kit-live:volume-discount:tier-change, e.g. to read the selected tier’s quantity. See Listen for tier changes.
  • Watch the discounted state — if you only care about whether this element is showing a discount, observe its data-dkl-discounted attribute (set while a tier is active) with a MutationObserver:
// Handles any number of <dkl-price> elements on the page
document.querySelectorAll('dkl-price').forEach((price) => {
  new MutationObserver(() => {
    const discounted = price.hasAttribute('data-dkl-discounted')
    // e.g. flag the surrounding card while a discounted tier is selected
    price.closest('.product-card')?.classList.toggle('is-discounted', discounted)
  }).observe(price, { attributes: true, attributeFilter: ['data-dkl-discounted'] })
})

Examples

For the full list of data-* attributes you can set, see Styling & Data Attributes.
Override attributes + tokens
<dkl-price
  data-show-savings="true"
  data-savings-format="amount"
  data-savings-label="You save"
  style="
    --dkl-price-font-size: 1.4rem;
    --dkl-price-font-weight: 700;
    --dkl-price-sale-color: #c0392b;
    --dkl-price-compare-opacity: 1;
  "
></dkl-price>
Listen for price changes
// The recommended hook: fires whenever the displayed price updates, with the
// previous and new price states.
document.addEventListener('discount-kit-live:price:change', (event) => {
  const { productId, previousPrice, currentPrice } = event.detail.resource

  const fmt = (cents) =>
    (cents / 100).toLocaleString(undefined, {
      style: 'currency',
      currency: window.Shopify?.currency?.active ?? 'USD',
    })

  console.log(
    `Product ${productId}: ` +
      `${previousPrice ? fmt(previousPrice.priceCents) : '—'}${fmt(currentPrice.priceCents)}` +
      (currentPrice.discounted ? ' (discounted)' : ''),
  )
})
Listen for tier changes
// React to volume-tier selections to drive your own UI alongside the price —
// here, a custom "Buy N at X each" summary element somewhere on the page:
//   <p data-tier-summary="7820000000001" hidden></p>
const summary = document.querySelector('[data-tier-summary]')

const money = (major) =>
  major.toLocaleString(undefined, {
    style: 'currency',
    currency: window.Shopify?.currency?.active ?? 'USD',
  })

document.addEventListener('discount-kit-live:volume-discount:tier-change', (event) => {
  const { productId, currentTier } = event.detail.resource

  // Scope to the product this summary belongs to — handy when several pickers
  // / prices share a page (e.g. the main product plus recommendations).
  if (productId !== Number(summary.dataset.tierSummary)) return

  // currentTier is null when the shopper clears their selection.
  if (!currentTier) {
    summary.hidden = true
    return
  }

  // unitPriceCents is the per-item price; discountAmount is a percentage for
  // 'percentage' tiers, or a major-unit amount for 'fixedAmount' tiers.
  const { quantity, unitPriceCents, discountType, discountAmount } = currentTier
  const saving =
    discountType === 'percentage' ? `${discountAmount}% off` : `${money(discountAmount)} off each`

  summary.hidden = false
  summary.textContent = `Buy ${quantity}+ at ${money(unitPriceCents / 100)} each — ${saving}`
})

Next steps

Styling & Data Attributes

Every data-* attribute, --dkl-* token, and CSS part.

App block

The no-code, theme-editor placement.