Skip to content
Docs

JavaScript API

Everything a trigger element can do, code can do too. The Components app embed defines a global window.DiscountKitLive synchronously on every page, so the quickview can be opened from any script — with or without a <dkl-quickview> tag on the page. The dialog’s bundle is loaded lazily on first use.

Opens the dialog and returns a promise that resolves once the product has loaded and rendered, or rejects if the bundle fails to load, the product isn’t found, or the dialog is closed (or superseded by another open) before the product arrives.

try {
const { panel, productHandle, productId } = await window.DiscountKitLive.openQuickview({
productHandle: 'awesome-tee',
variantId: 41200000000001,
})
// panel === 'product': the product is loaded and rendered
} catch (err) {
// bundle failed to load, product not found, or closed before load
}
  1. The dialog bundle is loaded if this is the first open on the page.
  2. The dialog opens at once — on a skeleton for a single product, on the picker for several — and discount-kit-live:quickview:opened fires.
  3. The product is fetched (Storefront API when the embed carries the token, the Ajax API otherwise, or read from a Liquid seed with no request) and rendered; discount-kit-live:quickview:loaded fires and the promise resolves.
  4. From here the dialog runs on events: variant-change as the shopper picks options, add-to-cart on a successful add, closed when it goes away.

Calling openQuickview() while the dialog is already open replaces its content with the new product; the earlier call’s promise rejects as superseded. Only one dialog exists per page — every trigger, every call and the Gift Selector share it.

Option Type Default Purpose
productHandle string — The product (or productId)
productId string | number — The product by id; Storefront source
variantId number first available Variant to preselect
products choice[] — Two or more products: picker first
pickerHeading / optionsHeading string labels Header text per screen
closeOnAdd boolean false Close after a successful add
showQty / qty / minQty / maxQty / allowQtyChange true / minQty / 1 / ∞ / true The quantity stepper
lineProperties Record<string,string> — Line-item properties on the add
showVolume boolean true Volume pickers inside the dialog
mode 'product' | 'selection' 'product' selection = the Gift Selector
moneyFormat string shop’s Price formatting

The same fields as the trigger’s data-* attributes (see Styling & Data Attributes), in camelCase:

string

The product to load. Provide this or productId.

string | number

Product id (numeric or gid://shopify/Product/…) as a stable alternative to the handle. Resolved through the Storefront API source; pair it with a handle on the Ajax fallback.

number · default: (first available)

Variant to preselect once the product loads.

Array<{ productHandle?, productId?, variantId? }>

Two or more products open the product picker first. Every other option applies to whichever product the shopper picks — including a top-level variantId, which preselects on any choice that doesn’t set its own. Give each choice its own productHandle or productId rather than relying on the top-level ones, which are also inherited by a choice that omits them. See Multiple products.

string · defaults: Choose a product / Choose your options

Custom header headings for the picker and options screens. optionsHeading also fills the otherwise-empty header on single-product opens.

boolean · default: false

Close the dialog after a successful add-to-cart.

boolean · default: true

Show the quantity stepper. When false, the preset qty is what gets added.

number · defaults: minQty / 1 / unlimited

Preset quantity and its bounds. qty is clamped into [minQty, maxQty] and applies even when the stepper is hidden.

boolean · default: true

When false, the stepper is shown but inert — the preset qty is what gets added.

Record<string, string>

Line-item properties attached to every cart add from this open, e.g. { '_dkl.source': 'quickview' }. Prefix a key with _ to keep it hidden in most themes’ cart display.

boolean · default: true

Mount a Volume Picker per eligible volume discount inside the dialog. Nothing renders when the product has none; set false to opt out.

'product' | 'selection' · default: product

selection opens the dialog as the Gift Selector: slots filled from groups of product choices, a selection tray, and one write for the lot. Its fields (groups, slots, submitLines and the selection copy) are on the Gift Selector JavaScript API page.

string · default: shop money format

Money format string for price rendering.

The promise resolves with:

{
panel: 'product' | 'products', // 'products' = the picker rendered, nothing chosen yet
productHandle: string | null, // null on the picker
productId: number | null, // null on the picker
}
await window.DiscountKitLive.openQuickview({
products: [
{ productHandle: 'awesome-tee' },
{ productHandle: 'awesome-hoodie', variantId: 41200000000456 }, // per-choice preselect
{ productId: 9265883611348 },
],
pickerHeading: 'Choose your free gift',
optionsHeading: 'Choose your size',
closeOnAdd: true,
})
// Resolves with panel: 'products' once the picker renders

A product card’s own button, with the card’s variant. The card knows which variant its image shows; open on it, and close once the shopper has added:

card.querySelector('.quick-add').addEventListener('click', () => {
window.DiscountKitLive.openQuickview({
productHandle: card.dataset.handle,
variantId: Number(card.dataset.variantId),
closeOnAdd: true,
})
})

A fixed-quantity upsell. Sell two of something from a banner, with the stepper shown but locked, and tag the line so your reporting can see where it came from:

window.DiscountKitLive.openQuickview({
productHandle: 'travel-socks',
qty: 2,
allowQtyChange: false,
lineProperties: { _source: 'homepage-banner' },
})

Wait for the load, then react. The promise tells you which screen the open settled on; the events tell you what the shopper does next:

const result = await window.DiscountKitLive.openQuickview({ productHandle: 'awesome-tee' })
if (result.panel === 'product') analytics.track('quickview_viewed', { id: result.productId })
document.addEventListener('discount-kit-live:quickview:add-to-cart', (e) => {
const { productId, variantId, quantity } = e.detail.resource
analytics.track('quickview_added', { productId, variantId, quantity })
}, { once: true })

Open something the theme already rendered. Any element can be a trigger without markup changes — give it data-dkl-quickview="<handle>", or dispatch the command event from a script that has no element at all (a keyboard shortcut, a chat widget, a recommendations API callback):

document.dispatchEvent(new CustomEvent('discount-kit-live:quickview:open', {
detail: { resource: { productHandle: recommended.handle } },
}))

Let the shopper pick from a set. Two or more products open the picker first; it’s the same call the Gift Selector builds on, without slots or a tray:

window.DiscountKitLive.openQuickview({
products: [{ productHandle: 'tote-bag' }, { productHandle: 'beanie' }, { productHandle: 'socks' }],
pickerHeading: 'Complete the look',
closeOnAdd: true,
})

Closes the dialog. A no-op if nothing is open (or the bundle was never loaded).

Per-element methods and the open attribute

Section titled “Per-element methods and the open attribute”

Every attached <dkl-quickview> trigger gains two methods that open and close its product:

const trigger = document.querySelector('dkl-quickview[data-product-handle="awesome-tee"]')
trigger.openQuickview()
trigger.closeQuickview()

The open attribute does the same declaratively — add it to open, remove it to close. It’s also reflected while that trigger’s dialog is open, so you can observe it:

<dkl-quickview data-product-handle="awesome-tee" open>
<button type="button">Quick view</button>
</dkl-quickview>

If you’d rather not hold a reference to anything, dispatch a bubbling event from document or any element. These are fire-and-forget — there’s no promise — but they work from anywhere, including pages with no <dkl-quickview> tag (the runtime lazy-loads the dialog for you):

document.dispatchEvent(new CustomEvent('discount-kit-live:quickview:open', {
detail: { resource: { productHandle: 'awesome-tee', variantId: 41200000000001 } },
}))
document.dispatchEvent(new CustomEvent('discount-kit-live:quickview:close'))

resource accepts every field of openQuickview(), including products. Prefer the helper when you need the result; use the event when you just need it to happen.

The dialog’s text defaults to English. Override any subset globally by setting window.DklContext.quickviewLabels — for instance from your theme’s layout, so it’s in place before the dialog first opens:

layout/theme.liquid
<script>
window.DklContext = {
...window.DklContext,
quickviewLabels: {
addToCart: {{ 'products.product.add_to_cart' | t | json }},
close: {{ 'accessibility.close' | t | json }},
},
}
</script>
Key Default Where
dialogLabel Quick view The dialog’s accessible name
close Close Close button
back Back Back-to-picker button
loading Loading product… Loading state
addToCart Add to cart Add-to-cart button
adding Adding… Add-to-cart button, in flight
added Added to cart Add-to-cart button, after a successful add
unavailable Unavailable Add-to-cart button, no such variant
soldOut Sold out Add-to-cart button, sold-out variant
viewDetails View full details Link to the product page
quantity Quantity Stepper label
decreaseQuantity Decrease quantity Stepper − button
increaseQuantity Increase quantity Stepper + button
error Something went wrong. Please try again. Error message
from From Price-range prefix (multi-product cards, high-variant fallbacks)
chooseProduct Choose a product Picker screen heading
chooseOptions Choose your options Options screen heading
volumeHeading Buy [tier_qty]+ In-dialog volume picker tier heading
volumeUnit /ea In-dialog volume picker unit label
volumeDiscountLabel off each item In-dialog volume picker discount label
volumeUnavailable No discount available In-dialog volume picker unavailable label

Per-open headings (pickerHeading / optionsHeading, or the data-*-heading attributes) win over chooseProduct / chooseOptions. The selection tray’s labels — “Add gift 1 of 3”, “Change gift 1 of 3” and the rest — are on the Gift Selector page.