> For the complete documentation index, see [llms.txt](https://docs.akinon.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.akinon.com/tutorials/project-zero/composable-storefront-integration.md).

# Composable Storefront Integration

## <mark style="color:red;">Step 1: Understand What Changed</mark>

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.

## <mark style="color:red;">Step 2: Mount a Slot</mark>

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 />} />
```

#### <mark style="color:red;">Two rules matter in practice:</mark>

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.

#### <mark style="color:red;">**ChromeSlot Options**</mark>

| **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.                                                       |

## <mark style="color:red;">Step 3: Identify the Canonical Placeholder Slugs</mark>

#### <mark style="color:red;">**Chrome**</mark>

| **Area** | **Slug** |
| -------- | -------- |
| Header   | `header` |
| Footer   | `footer` |

#### <mark style="color:red;">**Page Bodies**</mark>

| **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`    |

{% hint style="info" %}
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.
{% endhint %}

#### <mark style="color:red;">Account</mark>

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`    |

## <mark style="color:red;">Step 4: Configure Composable Checkout</mark>

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.                                                                        |

#### <mark style="color:red;">Outlet Blocks</mark>

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.

## <mark style="color:red;">Step 5: Set the Theme Editor Origin Allowlist</mark>

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:

```
NEXT_PUBLIC_THEME_EDITOR_ORIGINS=https://your-omnitron-origin
```

* 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.

## <mark style="color:red;">Step 6: Review Migration Notes</mark>

* 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.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.akinon.com/tutorials/project-zero/composable-storefront-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
