- name
- sfnext-page-designer
- description
- Integrate Page Designer with Storefront Next using React decorators, component registry, and Region rendering. Use when creating merchant-editable pages, adding Page Designer components with @Component/@AttributeDefinition decorators, using fetchPageFromLoader, or rendering Regions. This is for the React/Storefront Next implementation — for classic ISML Page Designer, see b2c:b2c-page-designer.
# Page Designer Skill
This skill covers Page Designer integration in Storefront Next — building merchant-editable pages with React components, decorators, and the Shopper Experience API.
## Overview
Page Designer is Commerce Cloud's visual editor for merchants. In Storefront Next, page structure (regions, components, attributes) is fetched from the Shopper Experience API and rendered via a component registry and `<Region>` component.
| Concept | Role |
|---------|------|
| **Page** | Fetched in route loaders via `fetchPageFromLoader(args, { pageId })` |
| **Region** | Named area rendered with `<Region page={...} regionId="..." />` |
| **Component** | Content block with a `typeId` and attributes; registered in `@/lib/registry` |
| **Registry** | Static registry auto-generated by Vite plugin — do not edit by hand |
## Which Pages Use Page Designer
| Uses Page Designer | Does Not |
|--------------------|----------|
| Home (`homepage`), Category/PLP, Search, Product/PDP | Cart, Checkout, Account, Auth |
## Route Setup
### In the Loader
```typescript
import { fetchPageFromLoader, collectComponentDataPromises } from '@/lib/page-designer';
export function loader(args: LoaderFunctionArgs) {
const pagePromise = fetchPageFromLoader(args, { pageId: 'homepage' });
const componentData = collectComponentDataPromises(args, pagePromise);
return {
page: pagePromise,
componentData,
};
}
```
### In the Layout
```typescript
import { Region } from '@/components/region';
export default function HomePage({ loaderData: { page, componentData } }) {
return (
<div>
<Region page={page} regionId="hero" componentData={componentData}
fallbackElement={<HeroSkeleton />}
errorElement={<RegionError />} />
<Region page={page} regionId="content" componentData={componentData}
fallbackElement={<ContentSkeleton />} />
</div>
);
}
```
## Component Setup
### Metadata Class with Decorators
```typescript
import { Component, AttributeDefinition, RegionDefinition } from '@salesforce/storefront-next-runtime/design';
@Component('hero-banner', {
name: 'Hero Banner',
description: 'Full-width banner with image and CTA'
})
class HeroBannerMeta {
@AttributeDefinition({ type: 'image' })
image: string;
@AttributeDefinition()
headline: string;
@AttributeDefinition({ type: 'url' })
ctaUrl: string;
@AttributeDefinition()
ctaText: string;
@AttributeDefinition({ type: 'boolean' })
fullWidth: boolean;
}
```
### React Component
```typescript
export default function HeroBanner({ image, headline, ctaUrl, ctaText, fullWidth }) {
return (
<div className={cn('relative', fullWidth && 'w-full')}>
<DynamicImage src={image} alt={headline} />
<h1>{headline}</h1>
{ctaUrl && <a href={ctaUrl}>{ctaText}</a>}
</div>
);
}
```
See [Decorator Patterns Reference](references/DECORATOR-PATTERNS.md) for all decorator options.
### Components with Server Data
If a component needs server data (e.g., product carousel):
```typescript
// Export a loader for the component
export function loader({ componentData, context }) {
const clients = createApiClients(context);
return clients.shopperProducts.getProducts({
params: { query: { ids: componentData.productIds } }
}).then(({ data }) => data);
}
// Optional fallback during loading
export function fallback() {
return <CarouselSkeleton />;
}
// Component receives data as prop
export default function ProductCarousel({ data, ...props }) {
return <Carousel products={data.products} />;
}
```
See [Component Registry Reference](references/COMPONENT-REGISTRY.md) for registry details.
## Design Mode
Detect when running inside Page Designer:
```typescript
import { isDesignModeActive, isPreviewModeActive } from '@salesforce/storefront-next-runtime/design/mode';
// In loaders
const isDesignMode = isDesignModeActive(request);
const isPreview = isPreviewModeActive(request);
// Root layout exposes pageDesignerMode in loader data
// 'EDIT' | 'PREVIEW' | undefined
```
## MCP Tools
Use the B2C DX MCP server tools for Page Designer development:
1. **`storefront_next_page_designer_decorator`** — Adds decorators to components (auto mode or interactive)
2. **`storefront_next_generate_page_designer_metadata`** — Generates metadata JSON for Business Manager
3. **`cartridge_deploy`** — Deploys cartridge to Commerce Cloud
### Typical Workflow
1. Add decorators to component (use `storefront_next_page_designer_decorator` with autoMode)
2. Generate metadata JSON (`storefront_next_generate_page_designer_metadata`)
3. Deploy cartridge (`cartridge_deploy`)
## Best Practices
1. **Keep loaders synchronous** — Return promises for streaming
2. **Use registry** — Register components with proper `typeId`
3. **Handle design mode** — Adapt UI when `pageDesignerMode` is `'EDIT'` or `'PREVIEW'`
4. **Rebuild after changes** — Static registry regenerates at build time
5. **Use MCP tools** — Faster than hand-writing decorators and metadata
## Related Skills
- `storefront-next:sfnext-data-fetching` - Loader patterns for Page Designer routes
- `storefront-next:sfnext-components` - Component development patterns
- `b2c:b2c-page-designer` - Classic ISML Page Designer (NOT Storefront Next)
## Reference Documentation
- [Decorator Patterns Reference](references/DECORATOR-PATTERNS.md) - All decorator types and options
- [Component Registry Reference](references/COMPONENT-REGISTRY.md) - Registry setup and component loaders
View on GitHub