Page Designer is a visual, drag-and-drop content management tool for B2C Commerce that business users use to create, schedule, and publish personalized storefront pages without extensive developer intervention. It provides a low-code environment where merchants can build engaging consumer experiences, such as homepages, campaign landing pages, and product highlights, by using a library of reusable functional components. Developers build the reusable components that merchants use.
In Storefront Next, developers build Page Designer components as React components instead of ISML templates. ISML pages and templates aren’t used in Storefront Next.
How It Works for Developers
Developers build the underlying building blocks that business users later manipulate. To learn more about how to build reusable pages and components in Page Designer, see Page Designer Readme in GitHub.
Core Architecture
The Page Designer system is built on these fundamental concepts that define how content is structured and rendered.
Pages: Top-level containers fetched via the ShopperExperience API that serve as the foundation for the storefront experience.
Regions: Named areas within a page or component that act as placeholders where components can be nested.
Components: Reusable UI elements, such as heroes, carousels, and grids, that contain specific functional logic and styling.
Component Data: Asynchronous data retrieved by component-specific loaders to populate the UI elements.
Implement Page Designer Components
Page Designer components are React components that you can decorate with metadata. You can configure the metadata in Business Manager.
Component Structure
Every Page Designer component follows this structure.
1src/components/my-component/2├── index.tsx # Main component with decorators
Metadata Decorators
Components use three decorators to define their metadata.
Decorator
Purpose
@Component
Registers the component with Page Designer.
@AttributeDefinition
Defines configurable attributes.
@RegionDefinition
Defines nested regions for container components.
Basic Component Example
This code example defines a Hero Banner Page Designer component. @Component registers the banner, and @AttributeDefinition on HeroMetadata declares optional configurable fields, such as Title, Image, and CTA link, a call-to-action link. A fallback export renders a loading skeleton. The default export is the main Hero that shows the image, title, and optional CTA. You can configure the Hero Banner in Page Designer.
These attribute types are available for @AttributeDefinition.
Type
Description
string
Single-line text
text
Multi-line text
markup
Rich text/HTML
integer
Whole numbers
boolean
True or false toggle
image
Image picker
url
URL input
product
Product picker
category
Category picker
page
Page reference
enum
Dropdown selection
cms_record
CMS content reference
Component Patterns: Fallbacks and Loaders
Fallback Components
We recommend that every Page Designer component exports a fallback function. The fallback skeleton is shown while the component loads.
1// Lightweight skeleton - no heavy logic2export function fallback({ title }: Partial<MyComponentProps>) {3 return (4 <div className="h-48 bg-gray-200 animate-pulse rounded">5 {title && <span className="sr-only">Loading {title}</span>}6 </div>7 );8}
Best Practices:
Keep fallbacks lightweight (no state, effects, or data fetching).
Match the approximate dimensions of the real component.
Use CSS animations for loading indication.
Data Loaders
Export a loader object for components that need dynamic data.
This code example defines a ProductCarousel that gets its list from a dual loader. A server loader calls fetchProducts using component.data?.categoryId and returns products. The component loads data on the server only, therefore the client loader returns null. The component receives already-resolved data and title as props—no Promise handling in the component. It renders the title and a list of products as ProductCards.
1// Server-side data loading2export const loader = {3 server: async ({ component, request, context }) => {4 // Fetch data on the server5 const products = await fetchProducts(component.data?.categoryId);6 return { products };7 },8 client: async ({ component, request }) => {9 // Optional: Client-side data loading10 return null;11 },12};1314export default function ProductCarousel({ data, title }: ProductCarouselProps) {15 // `data` is already resolved - not a Promise!16 return (17 <div>18 <h2>{title}</h2>19 {data?.products.map((product) => (20 <ProductCard key={product.id} product={product} />21 ))}22 </div>23 );24}
Key Points:
The data prop is always resolved when your component receives it.
The internal Component wrapper handles Promise resolution.
Your fallback is shown while data loads.
Multiple components load data in parallel.
Components with Regions
Container components can define the regions where other components can be placed.
This code example defines a Grid Layout Page Designer component that acts as a container with two regions. @Component registers it and @RegionDefinition declares Main Content with up to 6 components, and Sidebar with up to 3 components. GridMetadata adds an optional Columns attribute. A fallback export renders a simple loading grid. The default Grid component renders a two-column layout and uses the Region component to render the nested content for main and sidebar. That way, you can place other components in each region in Page Designer.
These options are available for the region definition metadata.
1@RegionDefinition([2 {3 id: 'content', // Required: Unique region ID4 name: 'Content Area', // Required: Display name in Business Manager5 maxComponents: 5, // Optional: Maximum components allowed6 minComponents: 1, // Optional: Minimum components required7 componentTypeInclusions: [ // Optional: Only allow these component types8 'sfnext.hero',9 'sfnext.productCarousel',10 ],11 componentTypeExclusions: [ // Optional: Disallow these component types12 'sfnext.grid', // Prevent nested grids13 ],14 },15])
Implement Page Designer Pages
A Page is the route-level definition that defines where Page Designer content can be placed.
Page Structure
This code example defines a Category Page with @PageType and two page regions: banner and promoContent. The route loader loads page and category data via fetchPageWithComponentData. The page component renders, in order: the banner region (with a skeleton fallback), a fixed ProductGrid for the category, and the promoContent region. Banner and promo slots are configurable in Page Designer. The route’s category defines the product grid.
arch_type: "headless": All generated metadata includes arch_type: "headless". This flag tells Page Designer that the page or component is rendered by the headless storefront (Storefront Next) rather than by a B2C Commerce controller. When Page Designer opens a page marked as headless, it loads the Managed Runtime (MRT) storefront URL in the editor iframe instead of a classic B2C Commerce controller-based page. This behavior enables Page Designer to render and edit React components directly.
route: Automatically extracted from your file-based routing structure (for example, src/routes/category.$categoryId.tsx → /category/:categoryId). When Page Designer loads a page, the {page_route} variable in the iframe URL is resolved using the route field from the page type metadata.
Manual additions: If you must add metadata manually, place JSON files in the cartridges/ directory structure.
Deploy Cartridges
Deploy the generated cartridge to your B2C Commerce instance.
Prerequisites
Create a dw.json file in the storefront-next-dev package directory.
Cartridge Path: Add app_storefrontnext_base to your site’s cartridge path in Business Manager.
Go to Administration > Sites > Manage Sites > [Your Site] > Settings.
Add app_storefrontnext_base to the cartridge path.
MRT Linking: Make sure that your MRT environment is linked to your B2C Commerce instance. The MRT environment is linked if the storefront was set up in Business Manager, or you can link it in MRT’s Environment Settings page. The MRT storefront URL in Page Designer is automatically configured when exactly one MRT environment is linked to the specific B2C Commerce instance and site ID. No manual URL configuration is required. Page Designer uses this URL to populate the headless_url object, (containing edit_url, preview_url, and info_url) that controls where the editor iframe points.
If the Page Designer iframe appears blank, verify that your MRT environment is correctly linked to your B2C Commerce instance and site.
Using Page Designer
Go to Merchant Tools > Content > Page Designer.
Create a page or edit an existing one.
Select a page type that matches your Storefront Next page types.
Add components to regions using the visual editor.
Configure component attributes in the properties panel.
Publish the page.
Page Assignment
You can assign pages to:
Specific entities - A particular product, category, or content asset
Default pages - Fallback for all entities of a type
Live Preview
When editing in Page Designer:
Business Manager reads the route from page metadata.
Loads your storefront in an iframe with the appropriate URL.
Shows live preview as you configure components.
For the storefront to load inside the Page Designer iframe, the frame-ancestors Content Security Policy directive must allow both 'self' and your Business Manager hostname (for example, https://your-instance.commercecloud.salesforce.com). The default value of 'self' isn’t sufficient. Extend the directive in config.server.ts. See Security Response Headers.
Previewing a local development environment in Page Designer isn’t supported. To use Page Designer’s live preview, deploy your storefront to a Managed Runtime environment. For a local development workaround, see Local Development.
Note
Shopper Context Preview
To preview a page in the context of a specific Customer Group or on a specific date:
Enable the feature toggle in Business Manager: Turn on the “Shopper Context” feature toggle in Business Manager.
Configure MRT environment variable: Set PUBLIC__app__features__shopperContext__enabled to true in your Managed Runtime environment.
Known Limitations
No live editing without saving: Changes made in the Page Designer properties panel aren’t reflected in the preview iframe in real time. You must save changes to see them in the preview.
Hybrid storefronts — link builder restriction: In hybrid deployments (SFRA and Storefront Next running together), the Page Designer link builder can only link to pages within the same technology stack. Headless pages can link to other headless pages, and SFRA pages can link to other SFRA pages, but cross-stack linking isn’t supported.
Local Development
Local development with Page Designer using localhost URLs isn’t supported. To test Page Designer integration, deploy your storefront to an MRT environment.
As a temporary workaround, use a local development cartridge to redirect Page Designer to your local server. Download the cartridge from Local Dev Cartridge (ZIP).
Setup Steps
Deploy the cartridge to your B2C Commerce instance.
Add the cartridge to your Business Manager cartridge path.
In Business Manager, go to Administration > SF Next Local Dev.
Enter your local development URL (for example, http://localhost:3000).
Run the service worker.
Click Enable Headless URL Override.
Click the checkbox only once. Due to a known UI limitation, the checkbox doesn’t reflect the correct state after toggling.
Important
Troubleshooting
Issue
Solution
Components don’t appear
Verify that the cartridge is in the cartridge path and deployed.
Page doesn’t load
Check that route in page metadata matches your routing.
Attributes aren’t configurable
Make sure that @AttributeDefinition decorators are correct.
Region is empty
Verify that regionId matches between code and metadata.
PD iframe is blank
Verify that your MRT environment is linked to the correct B2C Commerce instance and site ID. See Managed Runtime Administration.
Page Designer contains Storefront Next template pages that merchants can add and customize. Page Designer can connect to the storefront associated with a site. See
Page Designer Content Management for Merchants.
Content Slot Migration from SFRA
If you’re migrating from Salesforce Storefront Reference Architecture (SFRA) to Storefront Next and use content slots, follow this workaround until the planned Embedded Content feature becomes available. See Migrate Content Slots from SFRA to Storefront Next.