Images: render url, never path
url deliberately carries no resize parameters, because only the renderer knows the size. The Quickbutik image CDN takes imgix-compatible parameters, and the kit builds them:
- Vanilla
- React
- Web components
Helpers
Transform options:
width (w), height (h), dpr, quality (q), format (fm), fit, crop, background (bg), and auto, which defaults to "format" (pass null to drop it).
Behaviours worth knowing
- Images still processing are skipped. A freshly uploaded image exists before its file does, marked with
contentHash: "temp". PassincludePending: trueto include it. contentHashis appended as?v=, so a replaced image is not served stale. PasscacheBust: falseto turn that off.nullinstead of a broken URL. Render your own placeholder.<ProductImage>renders itsfallback(nothing by default) and<qb-product-image>gets anemptyattribute.- Only if you front the CDN yourself, set
imageBaseUrlon the client to the shop-scoped base without theproducts/segment, and the helpers completepathwith it. - If you use
next/image, add the CDN host (cdn.quickbutik.com) toimages.remotePatterns. Never use a wildcard pattern, which turns/_next/imageinto an open proxy.
Variant images
variant.imageId is the id of one of the product’s own images, or null when the variant has none. Swap the gallery when the shopper picks a variant, falling back to the main image:
Content sections
product.sections are the merchant’s content sections (“Size guide”, “Care”, “Delivery”) in their order: { id, title, content }. content is merchant-authored HTML: sanitize it before injecting it. Sections arrive rendered the way the Quickbutik theme renders them, with template text filled in and the [STOCKLEFT], [PRICE] and [BEFOREPRICE] merge tags replaced. Empty sections are left out.
Related products
products.get() (and so getBySlug()) returns relatedProducts: { mode, products }. list() and search() do not.
Each entry is a card-sized summary,
{ id, name, slug, price: { price, comparePrice }, image }, priced like the product list (automatic discounts and campaign prices included). Fetch the full product with products.get(id) when a card is opened.
imageId, sections and relatedProducts are typed from kit 1.5.0. The API serves them to older builds too; read them through a cast there.Money
Every amount in the kit and the Storefront API is an integer in minor units (öre, cents):24900 is 249,00 kr. Never a float, never a pre-formatted string. The MinorUnits type alias marks every such field.
formatMoney uses the currency’s real number of decimals, so JPY and ISK (which have none) are not divided by 100.
In React, the price hooks hand back raw
{ amount, currency } (the product’s own currency) and leave formatting to you. The web components format for you (price.display, cart.totalFormatted) because an HTML binding has nowhere else to do it; the raw integers (price.amount, item.lineTotal) are always there too.
Stock
variant.stock.stock is null when the shop does not track inventory (and for preorder items). null means purchasable, not sold out. Only a number at or below zero is out of stock. Never fabricate “only 3 left”.