For the complete documentation index, see llms.txt. This page is also available as Markdown.

Composable Storefront Integration

Step 1: Understand What Changed

Until now, a storefront area was either written in your project's code or built from Theme Editor sections — never both. From this release, every storefront area can be progressively taken over by the Theme Editor: you mount a slot where your own markup sits today, and your markup keeps rendering untouched until a designer publishes a composition for that area. Publishing a composition replaces your markup; unpublishing it gives your markup back.

This is opt-in per area. You can mount only the header, only the account pages, or the entire storefront. Nothing changes for an area you do not mount.

Step 2: Mount a Slot

Import ChromeSlot from @akinon/pz-theme and wrap the markup you want to make composable, passing that markup as the fallback:

<ChromeSlot slug="header" fallback={<Header />} />

Two rules matter in practice:

  1. ChromeSlot is an async server component. It cannot be used inside a client component. Mount a page-body slot in that route's layout rather than in the page, passing fallback={children}. This is the only pattern that works for routes whose page is a client component.

  2. Slugs are published content keys. Once a designer saves a composition against a slug, renaming that slug orphans their content. Use the slug names in the tables below exactly as written — some carry legacy suffixes on purpose.

ChromeSlot Options

Option

What it does

slug

Required. The placeholder the editor composes into. See the slug table below.

fallback

Your existing markup. Rendered whenever no composition is published for the slug.

pageContext

The commerce data the composed blocks read (product, listing, basket, account…). Build it with the page-context helpers so field names match what the blocks expect.

className

Class for the slot wrapper. Pass "contents" when the slot replaces a direct flex or grid child, so the wrapper does not become a box of its own and break the parent layout.

fallbackClassName

Class for the fallback wrapper on the live site. Pair it with className="contents" so your markup keeps owning its own layout classes.

sticky

Pins the slot to the top of the viewport. true for the defaults, an object to override top or zIndex, false to refuse the theme setting. Left unset, a composed header slot follows the designer's sticky-menu theme setting.

emptyZoneBand

Set false only when something else on the page already offers the takeover affordance for the same slug. Two competing calls to action for one slug is worse than none.

Step 3: Identify the Canonical Placeholder Slugs

Chrome

Area

Slug

Header

header

Footer

footer

Page Bodies

Page

Slug

Homepage

theme-homepage-body

Product detail

product-page-new

Product listing

list-page-body-new

Basket

basket-page-body

Auth

auth-page-body

Register

register-page-body

Forgot password

forgot-password-body

Guest login

guest-login-body

Order success

order-success-body

Order tracking

order-tracking-body

Stores

stores-page-body

FAQ

faq-page-body

Sitemap

sitemap-page-body

Brands

brands-page-body

Flat page

flat-page-body

404 page

not-found-body

500 page

server-error-body

Pages created from the editor itself resolve to page-<slug>. Modals resolve to modal-<id>, derived from a generated id rather than the modal's name, so renaming a modal never orphans its composition.

Account

The account shell slug renders on every account screen, so each subpage also has its own body slug. Without the per-subpage slugs, one composition would leak across orders, addresses, profile and the rest.

Screen

Slug

Account shell (all screens)

account-page-body

Account menu

account-menu

Dashboard

account-dashboard-body

Orders

account-orders-body

Order detail

account-order-detail-body

Addresses

account-address-body

Profile

account-profile-body

Change password

account-change-password-body

Change email

account-change-email-body

Coupons

account-coupons-body

Favourites

account-favourites-body

FAQ

account-faq-content

Contact

account-contact-body

Notifications

account-notifications-body

Stock alerts

account-stock-alerts-body

Step 4: Configure Composable Checkout

The checkout page is composable, but the payment internals are sealed. Payment forms, 3D Secure, agreements and place-order exist only in code and cannot be composed, restyled away or hidden. What a composition controls is placement: where the real flow, the step indicator and the summary render on the page, and what surrounds them.

Slug

Region

checkout-page-body

The full checkout body takeover. Outlet blocks placed here position the real checkout pieces.

checkout-top-body

A band above the flow, for trust content without rebuilding the page.

checkout-bottom-body

A band below the flow.

Outlet Blocks

Inside a checkout-page-body composition, three outlet blocks place the real pieces:

Outlet block

Places

checkout-flow-outlet

The real checkout flow. Also carries the composition's layout preference: one-page or step-by-step. Leaving it unset inherits your configured checkout.

checkout-steps-outlet

The step indicator.

checkout-summary-outlet

The order summary column.

Guarantees you can rely on:

  • If a composition contains no outlet for a piece, that piece renders in its normal place. Checkout can never lose its flow.

  • On a live storefront with no checkout composition published, the bridge adds no DOM at all.

  • Outlets only work inside the checkout body region. Placing one elsewhere does nothing.

  • The flow outlet has no visibility or display controls, so it is not possible to hide payment at any breakpoint.

  • Duplicate outlets for the same piece do not fight: the first one to mount claims the piece, the rest stay empty.

  • A composition cannot switch checkout between the standalone and the unified basket-and-checkout families. That stays a settings-only decision, which also makes a basket-to-checkout redirect loop impossible.

Step 5: Set the Theme Editor Origin Allowlist

The storefront now validates every message it receives from the Theme Editor against an origin allowlist, and no longer broadcasts messages to arbitrary origins. Set the editor origin on the storefront environment:

  • Multiple origins can be listed, separated by commas.

  • Localhost is trusted automatically outside production, so local development needs no configuration.

  • If the variable is not set in a production environment, the editor cannot attach to the preview and the storefront logs the reason.

Step 6: Review Migration Notes

  • The five native header starters were retired. They had no adoption and their runtime was never published. Compose the header through the header slot instead.

  • The checkout summary placeholder was removed. It rendered as a second full-width band under the flow and was indistinguishable from checkout-bottom-body; the summary column is owned by client code, so a slot could never land inside it. Anything meant to sit beside the summary now belongs in the checkout-page-body composition, arranged around the summary outlet. Projects generated by the CLI scaffold on 2.0.44 or later already reflect this.

  • Query parameters now reach the commerce backend on v1 product detail requests. Any storefront that relied on product detail requests ignoring query strings should smoke-test variant fetches after upgrading.

  • Storefronts compiling against an older es5 TypeScript target build again from 2.0.57 and 2.0.61. If you deferred an upgrade because of a type-check failure in the section renderer registry, it is resolved.

Last updated

Was this helpful?