Build your own UI
Headless mode hides Togenar’s built-in option panel while the configuration engine and SDK keep running. Your design system renders the swatches; the SDK drives the model.
1. Go headless
Section titled “1. Go headless”<togenar-embed id="tg" project="…" configurator picker="off"></togenar-embed>(mode="headless" is equivalent.)
2. Enumerate the options
Section titled “2. Enumerate the options”getOptions() returns every part with all of its variants, ready to render:
const parts = await tg.getOptions();/* [{ partId, partKey: 'body', label: 'Body', defaultVariantId, variants: [{ variantId, handle: 'walnut', label: 'Walnut', sku: 'OSLO-BODY-WALNUT', swatch, // color hex, when the variant defines one swatchImage, // swatch texture URL, when it defines one modelName, isDefault, available }, …] }, …] */Render these in your own components — swatch / swatchImage give you native-looking
pickers without re-deriving anything.
3. Drive the model
Section titled “3. Drive the model”Selection keys are the same handles getOptions() returned (they’re also what the
share URL uses after ?part=):
const { ok, selection } = await tg.select('body', 'walnut');select() resolves after the model swap settles — so you can update price, cart state
or imagery exactly when the shopper sees the change. It rejects on unknown handles.
reset() returns the configuration to the published default.
4. Keep it in sync with your catalogue
Section titled “4. Keep it in sync with your catalogue”// Live stock — false marks a variant out of stock:await tg.setAvailability({ body: { walnut: false, oak: true } });
// Price display — keyed by the same SKUs the events report:await tg.setPrices({ currency: 'EUR', locale: 'de-DE', items: { 'OSLO-BODY-WALNUT': 129.9 }, total: 259.8,});The viewer never computes prices — your page stays the single source of pricing truth. See Prices in the configurator.
5. Listen for changes
Section titled “5. Listen for changes”Even in headless mode the engine emits togenar:configurator:selection_change on load and
on every select() — treat it as your single source of selection state instead of
mirroring state in your own code.
