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

CartStore

Observable cart state shared by every component that asks for it. Lives outside React so a header badge and a cart page see the same object without either owning the other — the store is the single writer, components only ever subscribe. Built for useSyncExternalStore, hence the cached snapshot: that hook compares snapshots by identity and would loop forever on a freshly-allocated object.

Constructors

Constructor
Parameters
Returns
CartStore

Properties

clearCart()
Alias of clear, under the name a “clear the cart” search finds.
Returns
Promise<void>
getSnapshot()
Returns
CartSnapshot
subscribe()
Parameters
Returns
Returns
void

Methods

add()
cart.add resolves (and creates) the cart itself, so this path never asks the store for an id — that is what makes the very first “add to cart” a single round trip instead of create-then-add.
Parameters
Returns
Promise<Cart | null>
buyNow()
Add a product and start the checkout — checkout.buyNow() with the store kept in step. Does NOT navigate; useCheckout().buyNow and <qb-buy-now> do that with the url this resolves to. Why through the store at all, when the shopper is about to leave the page: they do not always leave. no-redirect keeps them here, a new-tab handoff keeps this tab open, and the back button restores the page from the back/forward cache exactly as it was — so a badge that missed the add would read one item short for the rest of the visit. The cart the add produced comes back on the result, so keeping the store right costs no extra request. Unlike the other mutations this one THROWS. A failed “buy now” is a failed checkout, which the caller has to show (and useCheckout keeps in its own error); stashing it on the cart snapshot would paint a cart error for something the cart did not do. The add may have landed before the handoff failed, though, so the cart is re-read on the way out — quietly: a re-read that fails too keeps the snapshot as it was rather than turning it into a cart error. Every failure is re-read, config errors included: most of those (a missing successUrl, a campaign mismatch) are thrown before anything is added, but a legacy handoff that comes back without an order id or a link throws one AFTER the add. The re-read is one quiet request on a failure path, and skipping it on the wrong error would leave the badge one item short.
Parameters
Returns
Promise<BuyNowResult>
clear()
Empty the basket — delete the remembered cart and forget it. Goes through cart.clear(), so a cart the server already dropped (404/410) still ends up cleared here rather than stuck in error with an id that can never be deleted. A no-op, with no request and no revision bump, when there is nothing to clear: a second click on “Töm varukorgen” is not a mutation.
Returns
Promise<void>
hydrate()
Adopt a cart fetched elsewhere (an RSC passing its result down).
Parameters
Returns
void
load()
Load the remembered cart if we have not already. Never creates one: mounting a cart badge must not write a cookie or a row for a visitor who has not added anything (crawlers included). Concurrent callers share one request.
Returns
Promise<Cart | null>
onMutation()
Be told about every successful mutation, with the cart before and after. Returns the unsubscribe function. See CartMutationEvent.
Parameters
Returns
Returns
void
refresh()
Re-read from the server, bypassing the “already loaded” short-circuit.
Returns
Promise<Cart | null>
removeItem()
Parameters
Returns
Promise<Cart | null>
updateItem()
Parameters
Returns
Promise<Cart | null>

Interfaces

AnalyticsProviderProps

Properties


AsyncState

Type Parameters

Properties


CartSnapshot

Extended by

Properties


CheckoutProps

Properties


ConsentBannerProps

Properties


ConsentBannerState

What the store exposes: the decision plus the one piece of UI state a banner and a far-away “Cookie settings” link have to share — whether the preferences panel is open. Not persisted.

Extends

Properties


ConsentContextValue

Properties


ConsentGateProps

Properties


ConsentProviderProps

Extends

Properties


ConsentSettingsButtonProps

Extends

  • Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type" | "lang">

Properties


JsonLdProps

Properties


ProductAddToCartState

Properties


ProductImageOptions

Which image to show, and at what size. Shared by <ProductImage /> and useProductImage.

Extended by

Properties


ProductImageProps

Which image to show, and at what size. Shared by <ProductImage /> and useProductImage.

Extends

  • ProductImageOptions.Omit<ComponentPropsWithoutRef<"img">, "src" | "srcSet" | "width" | "height" | "alt">

Properties


ProductImageState

What useProductImage resolved.

Properties


ProductOptionGroupProps

Extends

Properties


ProductOptionValuesProps

Extends

Properties


ProductProviderProps

Properties


ProductState

Properties


SeoProps

What the page is about. Exactly one of these shapes is used.

Extends

Properties


SeoProviderProps

Site-wide values every page shares. Supply once (via SeoProvider or as an argument) so a page only has to name what is specific to it.

Extends

Properties


ShopkitConsentOptions

The consent prop of <ShopkitProvider> as an object: the consent store’s options, the default banner’s, and the analytics switch.

Extends

Properties


ShopkitContextValue

Properties


ShopkitProviderProps

Properties


UseCartResult

Extends

Properties


UseCheckoutResult

Properties


UseConsentResult

What the store exposes: the decision plus the one piece of UI state a banner and a far-away “Cookie settings” link have to share — whether the preferences panel is open. Not persisted.

Extends

Properties


UseCurrencyResult

What a currency choice means for one shop. See describeCurrency.

Extends

Properties


UseOrderConfirmationOptions

Properties


UseOrderConfirmationResult

Properties


UseTrackPurchaseInput

Properties


UseTrackPurchaseResult

Properties

Type Aliases

CartStatus


ShopkitAnalyticsOptions

What consent={{ analytics }} takes: the <AnalyticsProvider> props.

Variables

AnalyticsContext


ConsentContext


ShopkitContext

Functions

AddToCart()

Add-to-cart bound to the selection, with its own disabled/pending state.

Parameters

Returns

ReactNode

AnalyticsProvider()

Analytics and pixels for the tree below, gated on the shopper’s consent. Sits inside a shop context (it needs the client and the cart store) and inside a consent provider (it reads the decision from there). One hub is created for the lifetime of the provider; the product, search, cart, checkout and confirmation surfaces below it report into the hub on their own, and useAnalytics() is for everything else.
With auto (the default) the merchant’s own GA4, GTM and Meta ids are read from the shop and loaded — the same ids the hosted checkout loads, so the storefront and the checkout report into the same properties. Nothing from Google or Meta is loaded before the shopper decides: Google on analytics (Consent Mode’s denied default and the update pushed first), Meta on marketing. loadBeforeConsent opts Google into loading earlier, in Consent Mode denied. <ShopkitProvider> mounts one of these by default (see its consent prop), so most storefronts never render it themselves. Rendered inside a tree that already has a hub, it joins that hub: its destinations are added, and the pixels are not loaded a second time.

Parameters

Returns

ReactNode

Checkout()

The Quickbutik checkout, inside your own page.
Renders one <div> and lets checkout.mount() put the frame inside it. The session is created once, from the props as they are at that moment: changing successUrl afterwards does NOT rebuild the checkout, because doing so would discard a session the shopper may be mid-payment in. The handlers are read live, so passing an inline arrow costs nothing. It follows the cart, exactly as <qb-checkout> does. While the cart is still loading or has nothing in it, nothing is mounted and nothing is reported as an error — onEmpty fires once, and the frame goes in when items exist. Change the cart from the page while the frame is up — useCart()’s 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. If the page instead empties the cart (clear(), the last line removed) the frame comes down, because the session it shows names a cart that no longer exists, and the next item added starts a fresh session. A redirect payment method is handled for you, exactly as <qb-checkout> handles it: when this page loads with ?qb_checkout_session= and qb_checkout_shop= on it — which is where the payment provider’s return bounces the shopper — the component RESUMES that session from those two values, whatever state the cart is in (it is normally gone by then, because the order exists), and takes the parameters back off the URL once the resumed frame has answered. Nothing else in the page has to know. See docs/checkout.md.

Parameters

Returns

Element

ConsentBanner()

The cookie banner. Headless first: hand it a render function and it renders exactly that, with the state and the actions a banner needs — the choices as a draft, save() to store them, acceptAll() / rejectAll() for the two buttons every banner has.
Without children it renders a minimal, accessible dialog of its own — the one place in the React layer that ships markup, because an empty consent banner is a compliance bug, not a styling choice. It comes styled (a stylesheet in @layer qb-consent, themed through --qb-consent-* custom properties, light and dark), and every rule targets the stable qb-consent* class names, so a site’s own CSS for them wins; unstyled leaves the stylesheet out. Accept-all and reject-all look the same, so neither is more prominent unless you make it so. The copy comes from consentLabels(lang, labels). Inside a <ShopkitProvider> that already shows the default banner, a <ConsentBanner> of your own replaces it rather than adding a second one. It renders nothing once the shopper has decided (unless showWhenDecided) and reappears when something calls openSettings() or reset(). On a server render without initialState on the provider it renders nothing until hydrated, so a shopper who already decided never sees it flash.

Parameters

Returns

ReactNode

ConsentGate()

Render something only once the shopper has allowed a category — a third-party widget that sets its own cookies, a marketing embed.
Undecided is denied, and so is a server render without initialState: the fallback goes out first and the content appears once consent is known.

Parameters

Returns

ReactNode

ConsentProvider()

The shopper’s cookie consent, for everything below it. Independent of <ShopkitProvider>: a decision is per page, not per shop, so this can sit above it (the usual place — the banner belongs to the page shell) or below it. One store is created for the lifetime of the provider and read from the qb_consent cookie in the browser.
Rendering on the server? Read the cookie there and pass it down, so the first byte already carries the right banner state and nothing flashes:
Without initialState the server renders as undecided and the banner waits for hydration before it shows anything, which is the flash-free fallback.

Parameters

Returns

ReactNode

ConsentSettingsButton()

The “Cookie settings” button for a footer: reopens the banner’s preferences panel, so a shopper can change their mind (or withdraw) long after the banner left. The React face of <qb-consent-settings>.
A real <button type="button">: opening a dialog is an action, not a navigation, so keyboard and screen-reader users get the right element. Every other button prop passes through; an onClick of your own runs first and can preventDefault() to keep the panel shut. Renders nothing without a consent provider above (consent={false} on the shop provider), so a footer does not have to know whether consent is on.

Parameters

Returns

ReactNode

JsonLd()

schema.org structured data as <script type="application/ld+json">. Split out from <SEO /> for the Next generateMetadata route, where the meta tags come from toNextMetadata() and this is the piece that has nowhere else to live:
Serialization escapes <, so a product name containing </script> cannot break out of the tag.

Parameters

Returns

ReactNode

ProductConsumer()

Escape hatch: the entire product state in one call, for a layout that needs several slices at once without nesting three render props.

Parameters

Returns

ReactNode

ProductImage()

A product image as an <img>, with the URL actually resolved. This exists because 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.
Unlike the other components in this package it does render markup — a single <img> and nothing around it. Every <img> attribute passes through, so className, style, sizes and onLoad all work as usual. For a different element (next/image, a CSS background) use useProductImage instead.

Parameters

Returns

ReactNode

ProductOptionGroup()

One named option group — for a layout that treats colour and size differently (swatches vs. a size row) rather than looping uniformly. Renders fallback when the product does not have that group, so the same component tree works for a product without colours.

Parameters

Returns

ReactNode

ProductOptions()

Every option group.

Parameters

Returns

ReactNode

ProductOptionValues()

Each value of one group, one call per value — the tightest form for a row of cards or swatches. children receives the value state (including selected and available); keying is the caller’s job, as with any mapped output.

Parameters

Returns

ReactNode

ProductPrice()

Price for the current selection. amount is null before a variant resolves, with min/max/isRange describing what is still reachable.

Parameters

Returns

ReactNode

ProductProvider()

Holds the variant selection for one product and derives everything from it. Renders nothing of its own — no element, no styling, no markup. It is a context provider and a state machine; the picker’s appearance is entirely the app’s. Read it with the hooks below, or with the render-prop components in product-components. It also resolves the product for you, so a route can hand it a slug, an id, or a promise instead of a loaded object:

Parameters

Returns

ReactNode

SelectedVariant()

The resolved variant, or fallback while the selection is incomplete — the natural place for “Select a size to continue”.

Parameters

Returns

ReactNode

SEO()

Every meta tag a Quickbutik page should have, from the product, category or shop you hand it. Inside a <ProductProvider> it needs nothing: the product and currency come from that context, and the canonical from the productPath template on <SeoProvider>.

Where the tags end up

React 19 hoists <title>, <meta> and <link> into <head> from anywhere in the tree, so this can be rendered inside the page component and the tags still land in the right place. That is the intended setup. On React 18 there is no hoisting: the tags render inline where the component sits. Crawlers do read <meta> in the body, but not reliably, and <title> will not work at all — so on 18, use useSeo with the framework’s own head mechanism instead. <script type="application/ld+json"> is never hoisted by React, and does not need to be: Google reads JSON-LD anywhere in the document, body included.

In Next.js App Router

Either works. generateMetadata + toNextMetadata() is the idiomatic route and gives Next control of the title — but Next’s Metadata has no slot for structured data, so pair it with <JsonLd> or the rich results are lost. Rendering <SEO /> alone emits both halves.

Parameters

Returns

ReactNode

SeoProvider()

Site-wide SEO values, so a page only names what is specific to it. Put it near the root with the things every page repeats — the storefront’s origin, the shop, the default share image:
Renders nothing of its own.

Parameters

Returns

ReactNode

ShopkitProvider()

Makes one client and one shared cart store available to the tree, and, by default, cookie consent with a banner and the shop’s own analytics gated on it (see the consent prop).
Both are created once and kept for the lifetime of the provider: a client rebuilt on every render would re-probe storage and, worse, hand every hook a new identity on every render.

Parameters

Returns

ReactNode

useAnalytics()

The analytics hub. Throws outside an <AnalyticsProvider>.

Returns

Analytics

useAsync()

Minimal fetch-on-mount hook. Intentionally NOT a cache: shopkit ships no data-layer opinion, so an app using TanStack Query or SWR keeps its own cache and simply calls the client directly. This exists for the common small case where pulling in a query library for one product grid would be the heavier choice. The fetch is aborted on unmount and on every re-run, and a resolved response from a superseded run is discarded — so a fast-changing dependency (a search box) cannot land an out-of-order result.

Type Parameters

Parameters

Returns

AsyncState<T>

useCart()

The shopper’s cart, shared across every component that calls this.
The cart is loaded on first mount and never created speculatively — a visitor who only browses causes no writes.

Returns

UseCartResult

useCategories()

One page of categories.

Parameters

Returns

AsyncState<Page<Category>>

useCheckout()

Hand the shopper off to the hosted Quickbutik checkout.

Returns

UseCheckoutResult

useClientCurrency()

The client’s current currency, re-rendering when it changes. The server snapshot is the configured default, so a server render and the first client paint agree even when the browser has a remembered choice — the client then re-renders with it.

Parameters

Returns

string | null

useConsent()

The consent decision and the actions on it. Throws outside a <ConsentProvider>, so a missing provider fails at the component that needs it rather than silently reading “undecided” forever.

Returns

UseConsentResult

useCurrency()

The currency the shop is browsed in, what the shop offers, and a setter — everything a currency switcher needs.
mode says what the choice means: "display" is shown converted and charged in the shop’s currency at checkout, "charge" is priced and charged in it, "base" is the shop’s own. The shop is read once per client (shop.get(), which needs checkout:read) and shared by every caller.

Returns

UseCurrencyResult

useOptionalAnalytics()

The hub when there is a provider above, null when there is not — for the kit’s own surfaces, which report when analytics is on and stay silent when it is not.

Returns

Analytics | null

useOptionalConsent()

useConsent() when there is a provider above, null when there is not.

Returns

UseConsentResult | null

useOptionalProductState()

The product state when there is a provider above, and null when there is not. For components that enhance a product view but must also work outside one — <SEO /> reads this so a page inside <Product> needs no product prop, while a page without one can still pass it explicitly.

Returns

ProductState | null

useOrderConfirmation()

Poll a checkout session until its order exists — the thank-you page hook. 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. Pass a session id, or omit it to use the one shopkit remembered when the session was created.
Took a snapshot on the server already (shopkit.checkout.confirmation() in the page)? Pass it as initialConfirmation. A terminal one (completed or failed) is the answer: nothing is polled, and the hook returns it from the first render, so the page renders final without a spinner. Anything else is where polling starts from. Inside an analytics hub (on by default under <ShopkitProvider>) a completed order is also reported as a purchase event, once per browser (the platform’s own dedup key), built from the session’s lines and total, whether it completed during the poll or arrived completed in initialConfirmation. Not with trackPurchase: false, and not when the checkout ran in inline success mode, where the embedded frame reports it itself. The legacy checkout has no session to build from; call useAnalytics().trackPurchase() yourself there.

Parameters

Returns

UseOrderConfirmationResult

useProduct()

A single product. data is null when it does not exist or is hidden. Priced for the client’s campaign storefront when it has one; pass storefrontId to price it for another (or null for none) — see ProductReadOptions. Priced in the client’s currency (or currency), and refetched when it changes.

Parameters

Returns

AsyncState<Product | null>

useProductAddToCart()

Add-to-cart wired to the current variant selection. Exists because every storefront otherwise rewrites the same guard: a product with options must not be addable until one variant is pinned, and the cart needs the variant id rather than the product id.

Returns

ProductAddToCartState

useProductImage()

Resolve a product image to a ready-to-render src / srcSet / alt. The hook twin of <ProductImage />, for a renderer this component cannot be — next/image, a background-image, an og:image:

Parameters

Returns

ProductImageState

useProductOption()

One option group by id or by name (case-insensitive), or null when the product has no such group — so a component written for “Color” degrades quietly on a product that has none.

Parameters

Returns

VariantOptionGroupState | null

useProductOptions()

The option groups to render as a picker. Empty for a simple product.

Returns

VariantOptionGroupState[]

useProductPrice()

Price for the current selection. amount is null until a variant is resolved; min/max/isRange describe what is still reachable, which is what a “from …” label should read.

Returns

VariantPriceState & object

useProducts()

One page of products.
Priced in the client’s currency (or params.currency), and refetched when setCurrency() changes it. Format with product.currency.

Parameters

Returns

AsyncState<Page<Product>>

useProductSearch()

One page of a server-side filtered, sorted catalog search.
Every parameter is a primitive, so the dependency list below is plain value equality — pass an inline object freely, it will not re-fetch on identity alone. A superseded request is aborted, which is exactly the behaviour a search-as-you-type box wants. Inside an <AnalyticsProvider> a search event is reported once per search term, when its results have landed — so a box that searches as the shopper types reports the terms that were actually shown, not every keystroke that was aborted on the way.

Parameters

Returns

AsyncState<Page<Product>>

useProductState()

The whole product state. Throws outside a <ProductProvider>.

Returns

ProductState

useSelectedVariant()

The resolved variant, or null while the selection is incomplete.

Returns

ProductVariant | null

useSeo()

The resolved head payload for a page, merged with the defaults in scope. Use this when the framework wants the data rather than the tags — a TanStack Start head(), an Astro layout, or a Next generateMetadata (with toNextMetadata). <SEO /> is this plus the rendering.

Parameters

Returns

SeoTags

useSeoDefaults()

The defaults in scope. Empty when there is no SeoProvider above.

Returns

SeoDefaults

useShop()

Shop name, logo, brand colour, default language, and its currencies (currency, currencies). For a currency switcher, useCurrency() reads the same data and adds the setter.

Parameters

Returns

AsyncState<Shop>

useShopkit()

The configured client. Throws a named error rather than returning null so a missing provider fails at the offending component instead of somewhere downstream where client is suddenly undefined.

Returns

ShopkitClient

useShopkitContext()

Returns

ShopkitContextValue

useTrackPurchase()

Report the purchase event from a thank-you page of your own. useOrderConfirmation does this for you; reach for this when you confirm the order some other way and only need the tracking. The purchase is built from the checkout session (cart_products, order_total) and deduplicated through the platform’s own localStorage key, so a reloaded page does not count the order twice.
No <AnalyticsProvider> above, or no order number yet, and it does nothing. A session the platform returns no order data for sets error; call useAnalytics().trackPurchase() yourself in that case.

Parameters

Returns

UseTrackPurchaseResult

References

Analytics

Re-exports Analytics

AnalyticsDestination

Re-exports AnalyticsDestination

AnalyticsDestinationContext

Renames and re-exports AnalyticsContext

AnalyticsOptions

Re-exports AnalyticsOptions

CommerceEvent

Re-exports CommerceEvent

CommerceItem

Re-exports CommerceItem

ConsentCategory

Re-exports ConsentCategory

ConsentChoice

Re-exports ConsentChoice

ConsentLabels

Re-exports ConsentLabels

ConsentSnapshot

Re-exports ConsentSnapshot

ConsentState

Re-exports ConsentState

ConsentStore

Re-exports ConsentStore

ConsentStoreOptions

Re-exports ConsentStoreOptions

PurchaseEvent

Re-exports PurchaseEvent