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 foruseSyncExternalStore, 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()
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()
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()
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()
Parameters
Returns
void
load()
Returns
Promise<Cart | null>
onMutation()
Parameters
Returns
Returns
void
refresh()
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
RenderProp<VariantOptionGroupState>
Properties
ProductOptionValuesProps
Extends
RenderProp<VariantOptionValueState>
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 (viaSeoProvider or as an
argument) so a page only has to name what is specific to it.
Extends
Properties
ShopkitConsentOptions
Theconsent prop of <ShopkitProvider> as an object: the consent store’s
options, the default banner’s, and the analytics switch.
Extends
Omit<ConsentStoreOptions,"initialState">
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
consent={{ analytics }} takes: the <AnalyticsProvider> props.
Variables
AnalyticsContext
ConsentContext
ShopkitContext
Functions
AddToCart()
Parameters
Returns
ReactNode
AnalyticsProvider()
useAnalytics() is for everything else.
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()
<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()
draft,
save() to store them, acceptAll() / rejectAll() for the two buttons
every banner has.
@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()
initialState: the
fallback goes out first and the content appears once consent is known.
Parameters
Returns
ReactNode
ConsentProvider()
<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.
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()
<qb-consent-settings>.
<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()
<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:
<, so a product name containing </script> cannot
break out of the tag.
Parameters
Returns
ReactNode
ProductConsumer()
Parameters
Returns
ReactNode
ProductImage()
<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.
<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()
fallback when the product does not have that group, so the same
component tree works for a product without colours.
Parameters
Returns
ReactNode
ProductOptions()
Parameters
Returns
ReactNode
ProductOptionValues()
children receives the value state (including selected
and available); keying is the caller’s job, as with any mapped output.
Parameters
Returns
ReactNode
ProductPrice()
amount is null before a variant resolves,
with min/max/isRange describing what is still reachable.
Parameters
Returns
ReactNode
ProductProvider()
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()
fallback while the selection is incomplete —
the natural place for “Select a size to continue”.
Parameters
Returns
ReactNode
SEO()
<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()
Parameters
Returns
ReactNode
ShopkitProvider()
consent prop).
Parameters
Returns
ReactNode
useAnalytics()
<AnalyticsProvider>.
Returns
Analytics
useAsync()
Type Parameters
Parameters
Returns
AsyncState<T>
useCart()
Returns
UseCartResult
useCategories()
Parameters
Returns
AsyncState<Page<Category>>
useCheckout()
Returns
UseCheckoutResult
useClientCurrency()
Parameters
Returns
string | null
useConsent()
<ConsentProvider>, so a missing provider fails at the component that
needs it rather than silently reading “undecided” forever.
Returns
UseConsentResult
useCurrency()
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()
Returns
Analytics | null
useOptionalConsent()
useConsent() when there is a provider above, null when there is not.
Returns
UseConsentResult | null
useOptionalProductState()
<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()
completed, failed or timeout.
Pass a session id, or omit it to use the one shopkit remembered when the
session was created.
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()
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()
Returns
ProductAddToCartState
useProductImage()
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()
Parameters
Returns
VariantOptionGroupState | null
useProductOptions()
Returns
VariantOptionGroupState[]
useProductPrice()
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()
params.currency), and refetched when
setCurrency() changes it. Format with product.currency.
Parameters
Returns
AsyncState<Page<Product>>
useProductSearch()
<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()
<ProductProvider>.
Returns
ProductState
useSelectedVariant()
Returns
ProductVariant | null
useSeo()
head(), an Astro layout, or a Next generateMetadata (with
toNextMetadata). <SEO /> is this plus the rendering.
Parameters
Returns
SeoTags
useSeoDefaults()
SeoProvider above.
Returns
SeoDefaults
useShop()
currency, currencies). For a currency switcher, useCurrency() reads
the same data and adds the setter.
Parameters
Returns
AsyncState<Shop>
useShopkit()
client is suddenly undefined.
Returns
ShopkitClient
useShopkitContext()
Returns
ShopkitContextValue
useTrackPurchase()
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.
<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