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.
DiscountKitLive.openQuickview(options)
Section titled “DiscountKitLive.openQuickview(options)”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}What happens on a call
Section titled “What happens on a call”- The dialog bundle is loaded if this is the first open on the page.
- The dialog opens at once — on a skeleton for a single product, on the picker for
several — and
discount-kit-live:quickview:openedfires. - 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:loadedfires and the promise resolves. - From here the dialog runs on events:
variant-changeas the shopper picks options,add-to-carton a successful add,closedwhen 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.
Options at a glance
Section titled “Options at a glance”| 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 |
Options
Section titled “Options”The same fields as the trigger’s data-* attributes (see
Styling & Data Attributes), in camelCase:
productHandle
Section titled “productHandle”string
The product to load. Provide this or productId.
productId
Section titled “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.
variantId
Section titled “variantId”number · default: (first available)
Variant to preselect once the product loads.
products
Section titled “products”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.
pickerHeading / optionsHeading
Section titled “pickerHeading / optionsHeading”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.
closeOnAdd
Section titled “closeOnAdd”boolean · default: false
Close the dialog after a successful add-to-cart.
showQty
Section titled “showQty”boolean · default: true
Show the quantity stepper. When false, the preset qty is what gets added.
qty / minQty / maxQty
Section titled “qty / minQty / maxQty”number · defaults: minQty / 1 / unlimited
Preset quantity and its bounds. qty is clamped into [minQty, maxQty] and applies even
when the stepper is hidden.
allowQtyChange
Section titled “allowQtyChange”boolean · default: true
When false, the stepper is shown but inert — the preset qty is what gets added.
lineProperties
Section titled “lineProperties”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.
showVolume
Section titled “showVolume”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.
moneyFormat
Section titled “moneyFormat”string · default: shop money format
Money format string for price rendering.
Result
Section titled “Result”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}Multiple products
Section titled “Multiple products”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 rendersExample Use Cases
Section titled “Example Use Cases”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,})DiscountKitLive.closeQuickview()
Section titled “DiscountKitLive.closeQuickview()”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>Command events
Section titled “Command events”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.
Labels & translations
Section titled “Labels & translations”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:
<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.