Skip to main content
Generated from the typings of @quickbutik/kit@1.8.0 as published on npm. Do not edit this page by hand: run npm run generate in tools/kit-api-reference. For guided, example-led documentation see the API reference.

Classes

ContextRequestEvent

The event itself. A class rather than a CustomEvent with a detail, because that is what the protocol specifies and what other libraries (Lit’s @lit/context, notably) listen for — an app already using Lit contexts can provide to, or consume from, these elements without an adapter.

Extends

  • Event

Type Parameters

Constructors

Constructor
Parameters
Returns
ContextRequestEvent<T>
Overrides

Properties

callback
context
subscribe

QbAddToCartElement

<qb-add-to-cart> — wraps the author’s own button and makes it work.
Adds no markup: the <button> is the page’s, with its own classes and its own label. What this contributes is the part every storefront otherwise rewrites — a product with options must not be addable until exactly one variant is pinned, and the cart needs the variant id rather than the product id. Any click inside it adds, so a whole card can be the target. It keeps the inner controls’ disabled in step with whether adding is possible right now, and reflects disabled / pending on itself for styling. Quantity comes from quantity="2", data-qb-quantity on the clicked element, or a nearby input[data-qb-quantity-input]. data-qb-action="add-to-cart" on a plain button inside <qb-product> does the same thing without the disabled-state management — use that when the button lives somewhere this element cannot wrap.

Extends

Constructors

Constructor
Returns
QbAddToCartElement
Inherited from
QbElement.constructor

Properties

observedAttributes

Methods

add()
Add the current selection. A no-op while the selection is incomplete, an add is already in flight, or the element carries disabled — the same guard the inner button’s disabled reflects, so a programmatic call cannot get past it either.
Parameters
Returns
Promise<void>
attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbBuyNowElement

<qb-buy-now> — “Köp nu”: add the selected variant and go straight to the hosted checkout.
The two halves of it are the two elements it is modelled on. From <qb-add-to-cart>: it must sit inside a <qb-product>, it is blocked until exactly one variant is pinned, quantity comes from quantity="2", data-qb-quantity on the clicked element or a nearby input[data-qb-quantity-input], and the inner controls’ disabled is kept in step. From <qb-checkout-button>: success-url, back-url and theme mean the same thing and are resolved by the same code, no-redirect stops short of navigating, and qb:checkout-started carries the handoff. The item goes into the REMEMBERED cart, so a basket the shopper already filled is checked out with it rather than replaced — “buy this too, now”, which is what the button means on every storefront that has one. The shared cart store sees the add, so a <qb-cart-count> on a page the shopper comes back to (the back button, no-redirect) is not one item short. Adds no markup. data-qb-action="buy-now" on a plain button inside <qb-product> does the same thing without the disabled-state management.

Extends

Constructors

Constructor
Returns
QbBuyNowElement
Inherited from
QbElement.constructor

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
buy()
Add the current selection, start the checkout and navigate. A no-op while the selection is incomplete (<qb-product> emits qb:add-to-cart-blocked with the groups still missing a choice), while one is already in flight, or while the element carries disabled. After it navigates it stays busy until the page is restored from the back/forward cache, so a click while the checkout loads buys nothing. no-redirect emits qb:checkout-started and stays put — for a page that opens the checkout in a new tab, or runs its own analytics first.
Parameters
Returns
Promise<void>
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbCartCountElement

<qb-cart-count> — the badge. Sets its own text to the number of items. The one element here that writes its own content, because there is nothing else it could be: a badge IS its number. zero is reflected as an attribute so an empty badge can be hidden in CSS.

Extends

Constructors

Constructor
Returns
QbCartCountElement
Inherited from
QbElement.constructor

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbCartElement

<qb-cart> — the shopper’s basket as a scope for the markup inside it.
Reflects state, empty and pending as attributes. Handles the clear (alias clear-cart) and refresh actions. clear empties the basket — deletes the remembered cart and forgets it — and does nothing when there is no cart; a cart the server already dropped still ends up cleared.

Extends

  • CartAwareElement

Constructors

Constructor
Returns
QbCartElement
Inherited from

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
connectedCallback()
Returns
void
Inherited from
disconnectedCallback()
Returns
void
Inherited from

QbCartItemsElement

<qb-cart-items> — one <template> clone per cart line. Scope inside a row: everything on the API’s CartItem, plus the formatted money fields (item.lineTotalFormatted, item.unitPriceFormatted, …) and item.onSale. Handles remove, increment and decrement, and binds any input[data-qb-quantity] in the row to that line’s quantity — with the change committed on change rather than on every keystroke, so typing 12 does not first send a quantity of 1. Rows are keyed by cart line id and reused across updates. Without that the quantity input the shopper is typing in is replaced mid-keystroke and loses both its value and the caret.

Extends

  • CartAwareElement

Constructors

Constructor
Returns
QbCartItemsElement
Inherited from

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
connectedCallback()
Returns
void
Inherited from
disconnectedCallback()
Returns
void
Inherited from

QbCheckoutButtonElement

<qb-checkout-button> — hands the shopper to the hosted Quickbutik checkout.
Adds no markup. A click anywhere inside creates the checkout session and navigates. Relative URLs are resolved against the current origin, so the markup above works unchanged in a rig, in a preview and in production. theme="dark" paints the hosted checkout dark for this shopper. Omit it and the merchant’s own choice applies — see checkoutTheme. Payment is deliberately not part of this: the hosted checkout owns the PSP integration, PCI scope, 3-D Secure and wallets. This creates the session, builds the handoff URL and sends the shopper there.

Extends

Constructors

Constructor
Returns
QbCheckoutButtonElement
Inherited from
QbElement.constructor

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
checkout()
Create the session and navigate. no-redirect stops it short of navigating and emits qb:checkout-started with the URL instead — for a page that wants to open the checkout in a new tab, or to run its own analytics first.
Returns
Promise<void>
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbCheckoutElement

<qb-checkout> — the Quickbutik checkout, inside your own page.
Adds one <iframe> and nothing else. The document inside is served from the checkout’s own origin, so the payment integration, 3-D Secure and the wallet domain registrations all work exactly as they do when the shopper is redirected — what changes is that they never leave your page. Not a replacement for <qb-checkout-button>: the button is still the right element for a cart page that hands the shopper off, and it is what this element degrades to when embedding is not possible (see below). Both create the session the same way, from the same attributes. theme="light" or theme="dark" paints the frame to match your own pages rather than following the theme the merchant chose for their shop. Read once with everything else, when the session is created — a page that toggles its own dark mode under a live checkout does not repaint it. See checkoutTheme. Four things happen automatically, and each is a thing a hand-rolled iframe would get wrong:
  1. The frame’s height follows its content, so there is never a scrollbar inside a scrollbar. min-height is the floor, and the height before the first measurement arrives.
  2. A redirect payment method breaks out to the top window. Klarna, Swish, Vipps/MobilePay, iDEAL, Trustly and a full-page 3-D Secure all navigate the whole window to the PSP, come back to the checkout’s own origin, and bounce to this page with ?qb_checkout_session=…&qb_checkout_shop=…. This element picks both up on load, resumes the same session from the URL alone — the cart, and the store id remembered with it, are normally gone by then, because the order exists — and, once the frame has answered, cleans the parameters out of the address bar so a reload does not try to resume a consumed session. If the resume never gets that far, the parameters stay, so a reload resumes again instead of starting a new checkout.
  3. It degrades rather than strands the shopper. A shop on the legacy checkout, a platform with no embed URL, or a page that cannot navigate its own top window all fall back to the redirect checkout and emit qb:checkout-fallback before any frame exists. A frame that is built but never answers — this page is not the origin the session was created for, most often — is taken down after 15 seconds and falls back the same way, with detail.reason === "handshake-timeout"; it never ends in state="error".
  4. It follows the cart. Change the cart from the page while the frame is up — Quickbutik.cart.add(), a quantity stepper of your own — and the checkout re-reads it and re-prices itself, so it never charges for a cart the shopper has already moved on from. Nothing is mounted while the cart is empty or still loading (qb:checkout-empty says so, once); the frame goes in when items exist. Empty the cart from the page — Quickbutik.cart.clear(), the last line removed — while a frame is up, and the frame comes down with it, because the session it shows names a cart that no longer exists; the next item added starts a fresh session. A frame that is resuming a return leg, or showing a completed order, is left alone: there the cart is SUPPOSED to be gone.
Events, all bubbling: qb:checkout-ready, qb:checkout-step, qb:checkout-event (GA4-shaped commerce events for your own dataLayer), qb:checkout-complete, qb:checkout-error, qb:checkout-fallback, and qb:checkout-empty when there is nothing in the cart to check out.

Extends

Constructors

Constructor
Returns
QbCheckoutElement
Inherited from
QbElement.constructor

Properties

observedAttributes
Deliberately empty. Every attribute here is read once, when the session is created. Re-reading one later would mean tearing down a checkout the shopper is standing in — possibly mid-payment — to build an identical one, so a changed attribute is ignored rather than obeyed. Change them before the element connects.

Accessors

checkout
Get Signature
The live embed handle, for a page that wants to drive it by hand.
Returns
EmbeddedCheckout | null

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbConsentBannerElement

<qb-consent-banner> — the cookie banner, headless.
Given no children it renders a minimal, accessible dialog of its own — the one exception to “the elements add no markup”, because an empty consent banner is a bug rather than a choice. The markup uses stable qb-consent* class names (the same ones the React <ConsentBanner> renders) and reads its copy from the built-in labels for lang, falling back to <html lang> and then English. It comes styled: one stylesheet in <head>, in @layer qb-consent so the page’s own rules win, themed through --qb-consent-* custom properties. unstyled leaves it out. A page configured through configure(), <qb-shop> or the script tag gets one of these appended to <body> automatically (consent is on by default). Placing one yourself replaces that one, so there is never a second dialog. Given children, it binds them instead, so a shop with its own voice writes its own banner:
Actions: accept-all, reject-all, save (reads every input[data-qb-consent] inside the banner), open-settings, close-settings. Scope: consent.status, consent.undecided, consent.decided, consent.open, consent.analytics, consent.marketing, consent.labels.*, consent.privacyPolicyUrl. Reflected: status="undecided|decided", open while the preferences panel is shown, and the native hidden attribute once the shopper has decided — unless show-when-decided is set, or the panel is open again (a <qb-consent-settings> link in the footer reopens it). The decision itself lives in the page’s ambient ConsentStore (see configureConsent), which writes the qb_consent cookie and dispatches qb:consent on document.

Extends

Constructors

Constructor
Returns
QbConsentBannerElement
Inherited from
QbScopeElement.constructor

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbScopeElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbScopeElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbScopeElement.disconnectedCallback
save()
Record what the checkboxes say. Missing inputs read as “no”.
Returns
void

QbConsentGateElement

<qb-consent-gate> — markup that exists only with consent.
The direct <template> child is the gated content; every other child is the placeholder. While the category is denied the placeholder shows and the template’s content is not in the document at all — an <iframe> or a <script> inside it is never fetched. When the shopper grants it, the content is cloned in after the placeholder and the placeholder is hidden; when they withdraw it, the clones are removed again. Reflects state="granted|denied".

Extends

Constructors

Constructor
Returns
QbConsentGateElement
Inherited from
QbElement.constructor

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbConsentSettingsElement

<qb-consent-settings> — a “Cookie settings” link, anywhere on the page.
A click anywhere inside reopens the banner’s preferences panel, however far away the banner is in the DOM — the two share the page’s consent store, and open lives in it. Reflects status="undecided|decided" like the banner, so the link can read “Cookie settings (analytics on)” through CSS or a binding of the page’s own. Left empty, it renders a <button type="button"> with the built-in label for lang (“Cookie settings”, “Cookie-inställningar”, …), the same thing React’s <ConsentSettingsButton> renders: an empty element would be a footer link nobody can click. Hidden when the page turned consent off.

Extends

Constructors

Constructor
Returns
QbConsentSettingsElement
Inherited from
QbElement.constructor

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbCurrencySelectElement

<qb-currency-select> — let the shopper pick the currency the shop is browsed in. Three ways to write it, from least to most markup:
Choosing calls client.setCurrency(): the choice is remembered, every <qb-product> and <qb-product-list> refetches its prices in it, and every cart element re-reads the SAME cart in it. A "display" currency is shown converted and charged in the shop’s currency at checkout; a "charge" currency is priced and charged in it. Scope: currency.code (what prices are shown in), currency.base, currency.mode (base / display / charge), currency.chargeCurrency, currency.count; inside a template row, option.code, option.label, option.name, option.mode, option.rate, option.selected, option.base. Rows get data-selected and data-currency. Reflects state, data-currency, data-mode, and empty when the shop offers nothing but its own currency — qb-currency-select[empty] { display: none } hides a switcher with nothing to switch. Emits qb:currency-change with { currency } after a choice. label="name" (or "code-name") labels the options with the currency’s name in locale. Reads the shop with shop.get(), so the key needs checkout:read — every standard storefront key has it.

Extends

Constructors

Constructor
Returns
QbCurrencySelectElement
Inherited from
QbScopeElement.constructor

Properties

observedAttributes

Accessors

info
Get Signature
What the current choice means for this shop, or null before it loads.
Returns
CurrencyInfo | null

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbScopeElement.attributeChangedCallback
choose()
Switch currency, exactly as a shopper’s choice does.
Parameters
Returns
Promise<void>
connectedCallback()
Returns
void
Inherited from
QbScopeElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbScopeElement.disconnectedCallback

abstract QbElement

Base for every element in this package. It exists for three things that every one of them needs and that are easy to get subtly wrong: not reading children before the parser has produced them, unwinding subscriptions on disconnect, and finding the shop. No shadow DOM anywhere. These are headless components: the merchant’s own stylesheet has to reach the markup, and a shadow root is precisely a wall against that.

Extends

  • HTMLElement

Extended by

Constructors

Constructor
Returns
QbElement
Inherited from

Methods

attributeChangedCallback()
Parameters
Returns
void
connectedCallback()
Returns
void
disconnectedCallback()
Returns
void

QbOptionsElement

<qb-options> — repeats its <template> once per option group the product actually has, in the product’s own display order. Scope inside a row: group.id, group.name, group.position, group.values, group.selectedValueId, group.chosen. A product with no options renders nothing and the element is marked empty, so qb-options[empty] { display: none } hides the surrounding chrome.

Extends

  • OptionsRepeatElement

Constructors

Constructor
Returns
QbOptionsElement
Inherited from

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
connectedCallback()
Returns
void
Inherited from
disconnectedCallback()
Returns
void
Inherited from

QbOptionValuesElement

<qb-option-values> — repeats its <template> once per value of the group it sits in. Nested inside a <qb-options> row it needs no attributes at all: the group comes from the row’s scope. Scope inside a value row: value.id, value.name, value.selected, value.available, value.unavailable, value.variantIds — plus everything the enclosing scopes offered. Each row’s top-level elements get data-selected and data-available reflected, aria-pressed set, and — on a <button> or <input> — the disabled property, so unavailable combinations are a stylesheet’s concern. option="<id or name>" is an escape hatch for the deliberate case: a layout that wants swatches for one particular group and a plain row for the rest. It is never required, and pinning it to a name means the picker stops working on a product whose merchant named that option something else.

Extends

  • OptionsRepeatElement

Constructors

Constructor
Returns
QbOptionValuesElement
Inherited from

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
connectedCallback()
Returns
void
Inherited from
disconnectedCallback()
Returns
void
Inherited from

QbOrderConfirmationElement

<qb-order-confirmation> — the thank-you page.
Order creation is asynchronous after payment, so a shopper can land here before the order is written. This polls with the platform’s own backoff and settles on completed, failed or timeout, reflecting each as both a scope flag and a status attribute. The session id comes from session-id, from a ?session_id= query parameter, or — with neither — from the session shopkit remembered when the checkout was created. With analytics on (configure({ analytics }), <qb-shop analytics>) a completed order is reported as a purchase event, once per browser, built from the session’s own lines and total. The hosted checkout never fires it in redirect mode — this page is the thank-you page, so this is where it belongs. no-track-purchase turns that off for a page that reports the order itself; in inline success mode the embedded frame already did.

Extends

Constructors

Constructor
Returns
QbOrderConfirmationElement
Inherited from
QbScopeElement.constructor

Properties

observedAttributes

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbScopeElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbScopeElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbScopeElement.disconnectedCallback

QbProductElement

<qb-product> — one product, its variant selection, and everything derived from the two. Resolves the product itself, so a page can name it by slug and write no JavaScript at all:
Renders no markup of its own. State is reflected as attributes — state="loading|ready|error", plus empty, complete / incomplete — so a skeleton and a “choose a size first” hint are pure CSS. The product can also be handed in as a property (el.product = product) when the page fetched it already. A slug lookup costs a catalog walk, because the storefront API has no slug filter. On a large catalog prefer resolving the product server-side and assigning the property.

Extends

Constructors

Constructor
Returns
QbProductElement
Inherited from
QbScopeElement.constructor

Properties

observedAttributes

Accessors

product
Get Signature
A product you already have. Wins over slug / product-id.
Returns
Product | null
Set Signature
Parameters
Returns
void
selection
Get Signature
The live selection state machine, for scripting a custom picker.
Returns
ProductController | null

Methods

addToCart()
Add the selected variant to the cart. A no-op resolving to null while the selection is incomplete: a product with options must not be addable until exactly one variant is pinned, or the cart gets a line the shopper never chose. The blocked attempt is emitted as qb:add-to-cart-blocked, carrying the groups still missing a choice, so a page can prompt for them.
Parameters
Returns
Promise<Cart | null>
attributeChangedCallback()
Parameters
Returns
void
Overrides
QbScopeElement.attributeChangedCallback
buyNow()
Add the selected variant and start the hosted checkout — “Köp nu”. Resolves to the handoff (url and all) and does NOT navigate; the buy-now verb and <qb-buy-now> do that. The guard is addToCart’s: while the selection is incomplete it emits qb:add-to-cart-blocked and resolves to null, because buying is adding. A second call while one is in flight also resolves to null — two clicks would otherwise add the item twice before either navigation lands. A failed handoff THROWS (see CartStore.buyNow); the verb and the element turn that into a qb:error. input may be a function, called only once the guard has passed — so a blocked click does not also warn about a missing success-url.
Parameters
Returns
Promise<BuyNowResult | null>
canAddToCart()
False while the selection is incomplete or a cart mutation is in flight.
Returns
boolean
connectedCallback()
Returns
void
Inherited from
QbScopeElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbScopeElement.disconnectedCallback

QbProductImageElement

<qb-product-image> — a product image as a real <img>, with the URL actually resolved. The one element in this package that renders markup, for the same reason React’s <ProductImage /> does: product.images[0].path is not a URL, it is the bare storage filename, and the shop’s storage prefix that completes it is not something a storefront credential can read. Rendering path directly is the single most common way a headless Quickbutik shop ships broken images.
It creates exactly one <img> and nothing around it, reusing the same node across updates so a swapped variant does not flash. Anything you put on the host as img-* is copied onto it (img-class, img-sizes, img-style), so the page keeps control of the markup.

Extends

Constructors

Constructor
Returns
QbProductImageElement
Inherited from
QbElement.constructor

Properties

image
A specific image record. Wins over every other way of choosing one.
observedAttributes

Accessors

product
Get Signature
The product to take the image from. Set by <qb-product-list> per row.
Returns
Product | null
Set Signature
Parameters
Returns
void

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbProductListElement

<qb-product-list> — a catalog grid, one <template> clone per product.
Scope inside a row: the whole Product, plus product.priceFormatted, product.image (the first image record) and product.href — the row’s link, built from the href-template attribute (/products/:slug by default). Every filter is an attribute, so a search box is list.setAttribute("search", q) and nothing else: the previous request is aborted and only the newest answer lands.

Extends

Constructors

Constructor
Returns
QbProductListElement
Inherited from
QbScopeElement.constructor

Properties

observedAttributes

Accessors

products
Get Signature
The products currently rendered.
Returns
Product[]

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbScopeElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbScopeElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbScopeElement.disconnectedCallback
reload()
Re-run the query. Useful after the catalog changed under a long session.
Returns
void

abstract QbScopeElement

An element that contributes to the view model its subtree is bound against. Scopes nest by extension, never by replacement: <qb-option-values> inside a <qb-options> row sees product, price, group and value, so a template can read anything an ancestor offered. That is what lets the variant picker be written without naming a single option type — the group and the value both arrive from the product, through the scope.

Extends

Extended by

Constructors

Constructor
Returns
QbScopeElement
Inherited from
QbElement.constructor

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbSeoElement

<qb-seo> — the page’s <head>, built from the product it sits next to.
Inside a <qb-product> it needs nothing else: the product comes from that context, and the canonical from the product-path template. It writes the title, the description, the canonical link, OpenGraph, the Twitter card and the schema.org JSON-LD — the last being where the actual rich-result value sits, price and availability included. Every tag it writes is tagged data-qb-seo, and it removes its own on update, so a soft navigation between products leaves no stale meta behind and nothing the page itself put in <head> is touched. A server-rendered page that already emits its head should not use this: two sources competing for one <title> is worse than either alone. Use buildSeo() from @quickbutik/kit in the renderer instead.

Extends

Constructors

Constructor
Returns
QbSeoElement
Inherited from
QbElement.constructor

Properties

observedAttributes

Accessors

tags
Get Signature
The resolved payload, for a page that wants the data rather than tags.
Returns
SeoTags

Methods

attributeChangedCallback()
Parameters
Returns
void
Inherited from
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

QbShopElement

<qb-shop> — an explicit shop for one subtree. Optional. The elements do not need this. A page configured once — by the script tag’s data-publishable-key, or by a configure() call — has an ambient shop that every element finds on its own, and that is how a storefront should normally be set up. Wrapping the whole page in a provider element is ceremony HTML does not need. What it is for is the handful of cases an ambient singleton genuinely cannot serve:
Consent and analytics are on by default, as they are for configure(): the merchant’s GA4 / GTM / Meta ids load for this shop, gated on the page’s consent, and a default <qb-consent-banner> is appended to the page when it has none (privacy-policy-url and lang here are handed to it). Inside a page whose configured shop is the same shop (a campaign <qb-shop storefront-id>), that shop’s analytics is reused rather than loaded twice, and this subtree’s cart reports into it. Renders nothing and adds no markup.

Extends

Constructors

Constructor
Returns
QbShopElement
Inherited from
QbElement.constructor

Properties

observedAttributes

Accessors

cartStore
Get Signature
The shared cart store for this subtree.
Returns
CartStore | null
client
Get Signature
A client built elsewhere. Wins over every attribute. A property rather than an attribute because a client is an object — the escape hatch for a server-rendered page, a custom fetch, or per-request cookie storage.
Returns
ShopkitClient | null
Set Signature
Parameters
Returns
void
initialCart
Set Signature
A cart already fetched on the server, so the first paint shows the real basket instead of an empty one that fills in a moment later. Stashed when it is assigned before the element starts — which is the normal case, since a page sets it immediately after inserting the tag.
Parameters
Returns
void

Methods

attributeChangedCallback()
currency and locale never rebuild the client. A rebuilt client means a new cart store, and a currency switch must keep the same cart — it is priced per request, so the current client is simply told the new currency (setCurrency) and everything below refetches.
Parameters
Returns
void
Overrides
QbElement.attributeChangedCallback
connectedCallback()
Returns
void
Inherited from
QbElement.connectedCallback
disconnectedCallback()
Returns
void
Inherited from
QbElement.disconnectedCallback

Repeater

Renders a <template> once per item, in place, keyed. Keyed matters more than it looks: a cart line whose quantity changes must keep its existing DOM, or the <input> the shopper is typing in is replaced mid-keystroke and loses both its caret and its focus. Rows are matched by key, moved rather than rebuilt, and only genuinely-gone rows are removed. The <template> is left in the DOM where the author put it — template content does not render — and rows are appended after it, so a heading or a “your cart is empty” paragraph written before it stays where it was.

Constructors

Constructor
Parameters
Returns
Repeater

Accessors

current
Get Signature
Every row currently rendered, in DOM order.
Returns
RepeatRow[]
hasTemplate
Get Signature
True once the host actually has a <template> to clone.
Returns
boolean

Methods

clear()
Remove every row. The <template> itself stays.
Returns
void
render()
Reconcile the rows against items. fill is called for every surviving row as well as every new one, because the data behind a stable key changes too — a cart line keeps its id while its quantity and total move.
Type Parameters
Parameters
Returns
void
rowFor()
The row a node sits inside, for resolving a per-row scope.
Parameters
Returns
RepeatRow | null

Interfaces

AutoBannerOptions

What the auto-mounted <qb-consent-banner> is given.

Properties


ConfigureOptions

Extends

Properties


Context

An opaque, comparable key for one kind of value.

Type Parameters

Properties


ContextProvider

Methods

dispose()
Stop answering and drop every subscriber.
Returns
void
update()
Re-deliver the current value to every subscriber.
Returns
void

DefinedElements

What defineElements registered, so a caller can see the real tag names.

Properties


DefineElementsOptions

Properties


ElementsConsentOptions

configure({ consent }) as an object: the page’s consent store options, plus what the automatically mounted banner is given.

Extends

Properties


MoneyView

Turning state into the plain objects data-qb-text="…" reads. The one thing added over what the SDK already returns is formatted money. React’s hooks deliberately hand back { amount, currency } and let the app’s design system format it; HTML bindings have no such escape, so every money field appears twice: the raw minor-unit integer, and a display string.

Extended by

Properties


PriceView

Turning state into the plain objects data-qb-text="…" reads. The one thing added over what the SDK already returns is formatted money. React’s hooks deliberately hand back { amount, currency } and let the app’s design system format it; HTML bindings have no such escape, so every money field appears twice: the raw minor-unit integer, and a display string.

Extends

Properties


ProductContextValue

What the picker elements need from the product above them. Separate from the scope: the scope is read-only data for bindings, this is the handle <qb-option-values> uses to actually change the selection. controller is nullable because the product is usually still loading when the elements below first ask. They subscribe, get null, render nothing, and are called again the moment it resolves — which is why they must be given a value now rather than left unanswered.

Properties

Methods

addToCart()
Parameters
Returns
Promise<Cart | null>
buyNow()
Add the selected variant and start the checkout, WITHOUT navigating — <qb-buy-now> decides that. Null when nothing was started (incomplete selection, one already in flight); throws when the handoff fails. input may be a function, called only once the guard has passed.
Parameters
Returns
Promise<BuyNowResult | null>
canAddToCart()
Returns
boolean

RepeatRow

One rendered row: the top-level elements one <template> clone produced. Plural because a template may legitimately have several roots (<dt> and <dd>, two <td>s), and all of them belong to the same item.

Properties


ShopContextValue

The shop every element works against: one client, one shared cart store, and the display preferences the bindings need in order to render money as a string.

Properties


VariantView

Properties

Type Aliases

ActionHandler()

Parameters

Returns

void

ContextCallback()

Type Parameters

Parameters

Returns

void

ElementsAnalyticsOptions

What configure({ analytics }) and <qb-shop analytics> build the hub from. The consent store is not an option here: the elements always use the page’s ambient one (see consent-context.ts), unless requireConsent is false.

Type Declaration


Scope

The view model a subtree’s bindings are resolved against. Plain data, deliberately: data-qb-text="price.formatted" is a path, not an expression, so there is no evaluator, no new Function, and nothing a merchant’s template can execute.

Variables

elementConstructors

The element classes, for registering a subset by hand.

productContext


scopeContext


shopContext

Functions

bindRow()

Bind a repeated row: each top-level element the template produced, and everything under it. Unlike bindSubtree the roots themselves are bound — the row’s markup is the author’s, and <li data-qb-text="item.productTitle"> is the obvious way to write a one-element row. A root that is itself a scope owner is left alone entirely; it will ask for its scope through the context protocol.

Parameters

Returns

void

bindSubtree()

Apply every binding inside host, not on host itself. What a scope-owning element calls on itself: <qb-product> binds the markup the author put in it, and its own attributes are configuration, not bindings. The walk stops at nested scope owners — they run their own pass with their own, extended scope. That is what makes <qb-option-values> inside a <qb-options> row see both group and value.

Parameters

Returns

void

buildShopAnalytics()

The analytics hub for one shop, started and wired the way every element expects: consent from the ambient store (unless requireConsent is false), cart mutations turned into add_to_cart / remove_from_cart, and — unless auto is false — the merchant’s own GA4 / GTM / Meta ids fetched from the platform and added as destinations once they arrive. Events tracked before then are remembered by the hub and delivered when they do. Shared by configure() and <qb-shop analytics>, so a hub built for a subtree behaves exactly like the page’s. Null when options is falsy.

Parameters

Returns

Analytics | null

cancelAutoBanner()

Withdraw the request, and take down the banner it mounted.

Returns

void

cartItemScope()

Parameters

Returns

Scope

cartScope()

The scope <qb-cart> contributes.

Parameters

Returns

Scope

configure()

Configure the shop the elements use, once, for the whole page. This is what makes <qb-shop> unnecessary. The script-tag build calls it automatically from its own data-* attributes, so a plain HTML page never writes any JavaScript at all:
A bundler consumer calls it directly, once, near their entry point:
Calling it again replaces the client and the cart store, which discards whatever the current store had loaded — so call it once, at startup, not per navigation. The remembered cart id itself lives in a cookie / localStorage and survives, so the new store re-reads the same cart. The analytics hub, when there is one, is destroyed and rebuilt with it; the consent store is only replaced when consent is given again.

Parameters

Returns

ShopContextValue

configureConsent()

Configure the consent store the elements share. Pass the options for a new store, or a store you already hold (one a React tree also uses, say). Call it before defineElements(): an element that has already started keeps the store it found.

Parameters

Returns

ConsentStore

createContext()

Type Parameters

Parameters

Returns

Context<T>

decorateHandoff()

A checkout handoff with the shopper’s consent on its URL. Every element that sends a shopper to the hosted checkout — <qb-checkout-button>, <qb-buy-now>, the buy-now verb — passes its result through here before it emits qb:checkout-started or navigates, so the URL a page sees in the event is the URL the shopper actually lands on. The consent comes from the page’s ambient store, the requireConsent rule from the shop’s hub; a page that configured neither, or turned consent off (configure({ consent: false })), keeps the URL untouched (see checkoutHandoffUrl).

Type Parameters

Parameters

Returns

T

defineElements()

Register the custom elements. Explicit rather than a side effect of importing, so @quickbutik/kit/elements stays tree-shakeable and a bundler can drop what an app does not use. The script-tag build calls it for you.
Idempotent: a name already registered is left alone, so calling it twice — or calling it after the script tag already did — is harmless rather than the NotSupportedError customElements.define would otherwise throw.

Parameters

Returns

DefinedElements

delegateActions()

Handle the verbs in handlers for anything inside host. click and change are both listened for: change is what a <select> of option values and a quantity <input> fire, and wiring them through the same attribute keeps one concept in the markup instead of two.

Parameters

Returns

ActionDelegate

disableAutoBanner()

The page wants no automatic banner (configure({ consent: { banner: false } }), data-consent-banner="false"): take down the one mounted, and refuse a <qb-shop>’s request for another until the page asks again.

Returns

void

getAmbientConsent()

The ambient consent store, or null when nothing has created one yet.

Returns

ConsentStore | null

getAmbientShop()

The ambient shop, or null when nothing has configured one yet.

Returns

ShopContextValue | null

hasShop()

True when a shop is configured at all — for a soft check before throwing.

Returns

boolean

isConsentDisabled()

Returns

boolean

isScopeOwner()

Parameters

Returns

boolean

markScopeOwner()

Parameters

Returns

void

money()

Format one amount, tolerating an unknown currency. Products and carts state the currency their amounts are in, and that is what callers pass. Only a platform older than product.currency leaves a product page with nothing to go on but the configured currency, and with none of those the honest options are a blank price or an unsymbolled number. It formats the number and says so once in the console, because a shopper seeing 1 299,00 understands it and a shopper seeing nothing does not.

Parameters

Returns

MoneyView

optionGroupScope()

Parameters

Returns

Scope

optionValueScope()

Parameters

Returns

Scope

priceView()

Parameters

Returns

PriceView

productScope()

The scope <qb-product> contributes.

Parameters

Returns

Scope

provideContext()

Answer context-request events raised inside host. produce receives the element that asked, so one provider can hand different values to different parts of its subtree — that is how a repeated row gives its own scope to the elements cloned into it without wrapping them in anything. Returning undefined declines the request and lets it keep bubbling to an outer provider.

Type Parameters

Parameters

Returns

ContextProvider

requestAutoBanner()

Ask for a default banner on the page: a <qb-consent-banner> appended to <body> once the document is parsed, unless the page already has one. A banner the page places itself, then or later, always wins: the auto-mounted one never duplicates it (see QbConsentBannerElement). Requests merge rather than replace, and the page’s own configuration outranks a <qb-shop>’s: scope: "page" (what configure() and the script tag pass) overrides what is already set, while a shop’s request only fills in what the page left out, and never brings back a banner the page turned off with disableAutoBanner().

Parameters

Returns

void

requestContext()

Ask for a context value. Returns whether anyone answered, which is what lets the elements fall back to the ambient shop when the page has no <qb-shop> at all — the common case, and the one the script tag is built around.

Type Parameters

Parameters

Returns

boolean

requireAmbientConsent()

The ambient consent store, created with the defaults if there is none.

Returns

ConsentStore

resetAmbientConsent()

Forget the ambient store. For tests, and for a hard teardown.

Returns

void

resetAmbientShop()

Forget the ambient shop. For tests, and for a hard teardown.

Returns

void

resolvePath()

"product.images.0.url" against the scope. Missing anywhere → undefined, never a throw: a template written for a product with images must not break the page on the one product without any.

Parameters

Returns

unknown

setAmbientClient()

Adopt a client you built yourself — a rig-pointed one, or one sharing a server-rendered cart. Replaces the ambient shop, keeping the display preferences and the analytics choice already configured.

Parameters

Returns

ShopContextValue

setCurrency()

Browse the ambient shop in another currency — client.setCurrency() on the client every element uses. Every <qb-product>, <qb-product-list> and cart element reprices; the choice is remembered. null returns to the configured default. Throws when nothing is configured.

Parameters

Returns

Promise<void>

stopActionWarnings()

Stop warning about unhandled actions. For tests, and for a hard teardown.

Returns

void

variantView()

Parameters

Returns

VariantView