How the storefront works
One small runtime, components that load when they appear, and a plain form when JavaScript is off.
The app embed
The Luxe app embed renders <luxe-root> with a <script type="application/json" data-luxe-settings> block, plus the cart drawer and tray hosts when they apply (the builder, the tray and the rewards bar carry their own data-luxe-config blocks). Configuration comes from metafields in Liquid: nothing is fetched over the network to start.
luxe-root.js is the only module every page loads: a registry that lazy-loads a component when its element appears, plus the cart client, event bus, consent-aware analytics and money formatting. TypeScript Web Components, bundled with esbuild, no framework.
Lazy modules
| Element | Loads |
|---|---|
luxe-kit-builder | luxe-kit.js, then picker, rows, quantity list, extras, upgrade, editor and Complete my set chunks as needed |
luxe-kit-tray, luxe-add-to-kit | luxe-tray.js, then luxe-tray-extras.js and luxe-tray-ms.js (the tier progress bar) as needed |
luxe-rewards-bar | luxe-bar.js |
luxe-cart-drawer | luxe-drawer.js on first cart interaction or idle, only with the Luxe cart drawer, then drawer modules (discount, offer, upsells, Rebuy, protection, content, unlock, empty bag) |
luxe-upsell | luxe-upsell-product.js |
[data-luxe-edit-line] on the theme cart | luxe-cart-edit.js, for Edit set |
Custom elements
| Element | DOM |
|---|---|
luxe-root | Light DOM, the runtime |
luxe-kit-builder | Light DOM, the Bundle set builder |
luxe-item-picker | Shadow DOM sheet or drawer |
luxe-kit-tray | Shadow DOM |
luxe-add-to-kit | Light DOM |
luxe-set-milestones | Shadow DOM: an unregistered host the tray fills (Tier progress bar block) |
luxe-cart-drawer | Shadow DOM, light-DOM hosts for your widgets |
luxe-rewards-bar | Light DOM |
luxe-upsell | Light DOM |
Every element carries data-luxe-version once its script has run.
How it degrades
| Situation | What happens |
|---|---|
| Embed off | No Luxe script runs; blocks render their no-JS markup; sets sell with their default picks |
| JavaScript blocked | A plain form posts the set with its house selection to /cart/add |
| Uninstalled | Blocks and embed disappear; products stay purchasable |
| Unknown theme cart | The Luxe drawer does not take over |
| B2B buyer | No script loads, unless B2B buyers is set to SAME; window.Luxe.b2b is true |
| Metafield missing or invalid | The component renders nothing |
Performance budgets
| Metric | Budget (gzipped) |
|---|---|
| Core JS (luxe-root and shared runtime) | ≤ 15 KB |
| Bundle set builder and picker | ≤ 14 KB |
| Cart drawer | ≤ 14 KB |
| Tray and Add to set | ≤ 8 KB |
| Rewards bar | ≤ 4 KB |
| Layout shift | CLS 0 |
| App proxy calls on the add-to-cart path | 0 |