@quickbutik/kit/elements is the same headless composition as the React layer, as custom elements: <qb-product>, <qb-cart>, <qb-checkout-button> and friends. Use it for anything that is not React: a plain HTML page, Astro, Vue, Svelte, Nuxt, a Rails, Laravel or WordPress view, Webflow, an existing jQuery theme.
- Light DOM, no shadow root. Your stylesheet reaches everything.
- No markup of their own. The elements bind data into markup you wrote, through
data-qb-*attributes, and reflect their state as attributes for your CSS. Four deliberate exceptions:<qb-product-image>renders an<img>,<qb-cart-count>writes its number,<qb-seo>writes into<head>, and<qb-checkout>renders the checkout’s iframe. - No CSS shipped. The elements reflect their state as attributes for your own stylesheet.
Do not mix the React layer and the elements on one page. Each brings its own cart store, and the two would not update together.
Choose a setup
- Script tag (no build step)
- With a bundler
One
<script> with the key on it configures the shop and registers every element. The page below it is markup only: no init call, no wrapper element.- Pin the version in the URL and cache-bust on upgrade.
- Use
defer. The elements cope with being upgraded mid-parse either way;deferkeeps the script off the critical path. - One self-contained file, no runtime dependencies, exposed as
window.Quickbutik.
window.Quickbutik API are in Scripting and the script tag reference.Import it only in the browser
@quickbutik/kit/elements defines classes that extend HTMLElement when it loads. Importing it in Node (an SSR entry, a frontmatter, a server file) throws ReferenceError: HTMLElement is not defined. The root entry @quickbutik/kit is the server-safe one; use it for server-side reads.
The ambient shop: there is no wrapper element
The shop is ambient: one client and one shared cart store per page, set up once byconfigure() or by the script tag’s data-publishable-key. Every element finds it on its own. An element that talks to the API and finds no shop reports a named ShopkitConfigError listing the three ways to provide one, sets state="error" and emits qb:error.
<qb-shop>: optional overrides
<qb-shop> exists for the cases a page-wide singleton cannot serve. A <qb-shop> ancestor wins for its own subtree; everything else keeps using the ambient shop.
It emits
qb:shop-ready with { client, cartStore, currency, locale }.
Set the currency
Products and carts state the currency their prices are in (product.currency, cart.currency), and the elements format with it. For a shop that sells in its own currency only, nothing needs configuring.
currency in configure() (or data-currency on the script tag) is the currency the page browses in: it is sent with every product, cart and checkout request, and a shop that offers that currency answers with converted prices. Leave it out to start in the shop’s own currency. It doubles as the formatting fallback for a platform older than product.currency.
setCurrency() and the switcher’s templates are covered in Currencies.
Consent and analytics
On by default. A page configured byconfigure(), <qb-shop> or the script tag gets the kit’s default cookie banner appended to <body> (unless it places its own <qb-consent-banner>), and loads the merchant’s own GA4, GTM and Meta pixel from the shop’s settings only after the shopper agrees. The elements report view_item, search, the cart events and the purchase, and every checkout handoff forwards the shopper’s decision to the hosted checkout.
Next steps
Templates and bindings
Bindings, repeats, actions and styling on state.
Build the storefront
Catalog, product page, cart, checkout and thank-you page.
Scripting
window.Quickbutik, events and recipes.Elements reference
Every element’s attributes, scope, reflected state and events.