# Preview states in the Customizer (/themes/preview-scenarios)

Merchants design pages against **states**, not only live data: an empty cart, a shopper with no
orders yet, a product with no reviews. The **Data** button in the Customizer's toolbar switches
those states per domain, and the canvas updates in place without a reload. The platform ships
domains for its own data (cart, orders, addresses), and **your theme can declare its own** for
any component.

## The merchant's view [#the-merchants-view]

The preview toolbar has these related controls:

- **Signed in / Guest** sets the canvas's sign-in state. **Guest** hides even a real session, so
  signed-out pages stay designable. **Signed in** fills a missing session with a sample
  customer, so account pages render.
- **Data** has one row per domain. Platform rows come first, and theme rows appear under
  **From your theme**. A dot on the button marks any choice other than the default. Rows that
  only apply to signed-in shoppers are dimmed in Guest mode.

Choices stay while the merchant navigates inside the canvas, and a change applies at once:
theme domains re-render, and platform domains reload the page's data.

## Built-in domains [#built-in-domains]

| Key         | Options (the first is the default) |
| ----------- | ---------------------------------- |
| `cart`      | With items / Empty                 |
| `orders`    | Sample orders / No orders yet      |
| `addresses` | Sample address / None saved        |

The platform applies these on the server, so your components receive the shaped data (an empty
order list, a sample cart) through the usual SDK hooks with no code of their own.

## Declare your own domains [#declare-your-own-domains]

Create `src/preview-scenarios.ts` in your theme and default-export the domains:

```ts title="src/preview-scenarios.ts"
import { definePreviewScenarios } from '@poltura/theme-sdk/editor';

export default definePreviewScenarios([
  {
    key: 'reviews',
    label: 'Reviews',
    options: [
      { value: 'live', label: 'Live data' },
      { value: 'sample', label: 'Sample' },
      { value: 'empty', label: 'None' },
    ],
  },
]);
```

The first option is the default. Set `requiresAuth: true` on a domain to dim its row while the
merchant previews the Guest state.

> Keep this file **pure data**. It is bundled into every page, and anything it imports comes
> along. Declare domains here and branch on them in your components.

## Read the active state in a component [#read-the-active-state-in-a-component]

```tsx
import { usePreviewScenario } from '@poltura/theme-sdk/editor';

export function ReviewCount({ count }: { count: number }) {
  const shown = usePreviewScenario('reviews') === 'empty' ? 0 : count;
  return <p>{shown} reviews</p>;
}
```

Outside the Customizer the hook **always returns the domain's default** (its first option), so
branching on it never changes what shoppers see. You need no guard around it.

The shipped themes carry a working example. Each declares the `reviews` domain in
`src/preview-scenarios.ts`. `Reviews` from `@poltura/theme-sdk/product` reads it and renders
live, sample or empty reviews. The Catalog, Editorial, Essential, Launch and Pop themes draw
it in `src/blocks/product-reviews.tsx`.

## Rules [#rules]

An entry that breaks a rule is skipped without an error, so the picker never breaks:

- Keys and option values use lowercase letters, digits, `-` and `_`, start with a letter or a
  digit, and are at most 32 characters long.
- A key must be unique and must not be a built-in key (`cart`, `orders`, `addresses`).
- A domain needs at least two valid options. Options after the sixth are ignored.
- Only the first 12 domains are used.
- Labels are cut to 40 characters.

## How it works [#how-it-works]

The storefront merges your declarations with the platform's domains and reports them to the
Customizer when the canvas loads. The picker shows whatever arrives, so a new domain needs no
admin change. The choices travel as a `preview_data` URL parameter that follows the merchant
through the canvas. When a choice changes, the Customizer tells the canvas, which rewrites that
parameter in place and reloads the data. The page itself never reloads.

Sample data renders only inside the Customizer's preview. A shopper who adds `preview_data` to a storefront URL
gets live data.

## Next [#next]

- [Customize the cart button](/themes/cart-button): restyle, move or replace the header cart.
- [editor reference](/themes/sdk/reference/editor): `definePreviewScenarios`,
  `usePreviewScenario` and `useIsEditing`.
