Skip to main content
The elements cover the common storefront with markup alone. When you need more, everything they use is reachable from script: the client, the shared cart store and a qb: event for everything that happens.

window.Quickbutik

The script-tag build exposes the whole kit as window.Quickbutik:
With a bundler, the same pieces are imports: configure() (returns { client, cartStore }) and getAmbientShop() come from @quickbutik/kit/elements; formatMoney, buildSeo, the image helpers, ProductController and AsyncResource come from @quickbutik/kit. Quickbutik.client is the full SDK client, so anything the elements do not do is a plain call:

The cart store

Quickbutik.cart (or configure().cartStore) is the one store every cart element reads. Mutations capture errors into error and resolve to null instead of throwing.
Use this store rather than a second client for cart work. A second client keeps its own state, so your code and the elements disagree until the next reload.

Events

Every element emits qb:-prefixed events that bubble and compose, so one listener on the document catches all of them.

Errors are mostly silent

Elements report failures as state rather than exceptions:
  • A failed product lookup sets state="error" on <qb-product>; no event, no console line.
  • A failed list sets state="error" and list.error.
  • A failed cart mutation is captured by the store: add() resolves null, none of qb:added, qb:added-to-cart or qb:error fires, the cart elements reflect state="error", and the message is in Quickbutik.cart.getSnapshot().error (not in the cart.* scope).
  • qb:error fires for startup failures (no shop, a bad key), a <qb-shop> that cannot build its client, a checkout that fails to start and a confirmation that cannot run.
Style [state="error"] and read the store when you need the message:

Recipes

A key from a server-rendered template

When the key is a template variable rather than a literal, load the library without auto-registration and configure it yourself:
type="module" matters. defer is ignored on an inline script, which would then run during parsing, before the deferred kit script has defined window.Quickbutik (Quickbutik is not defined). A module script runs after the deferred scripts before it, in order. Wrapping the code in a DOMContentLoaded listener also works.

Your own cart badge

Load more

Setting cursor on <qb-product-list> replaces the page. To append instead, bind the list’s next cursor into the markup, then fetch the following pages with the SDK and render the cards yourself:

A custom picker

document.querySelector("qb-product").selection is the live ProductController. Drive it from any UI and the element re-renders on every change:

Clear the cart

Inside a <qb-cart>, <button data-qb-action="clear-cart"> does the same with no script.
<qb-currency-select> with a <template> does the same in markup, and lists only the currencies the shop actually offers. See Currencies. no-redirect stops the navigation and hands you the URL, for example to pass an explicit cart id inside an app builder’s preview, where cookies are blocked:
Or skip the element and start the checkout with the SDK:

Content Security Policy

The bundle evaluates no strings (no eval, no new Function). With analytics off (data-analytics="false") it loads nothing else on its own, so this is the whole policy it needs:
With analytics on (the default), it loads the merchant’s own vendors once the shopper consents, and the policy must allow them as well:
Every tag it adds is async and carries data-qb-analytics.