Migrate Content Slots from SFRA to Storefront Next

In Storefront Next, React components replace ISML templates. If you’re migrating from Salesforce Storefront Reference Architecture (SFRA) and rely on content slots, use this workaround until the planned Embedded Content feature becomes available.

Content Slot Workaround Overview 

This workaround lets you manage reusable HTML content, such as shipping policies, disclaimers, or promotional blocks, in Page Designer and embed it across your storefront. It provides:

  • A “Content Slot Page” page type with a single content region.
  • A “Markup Content” component type with a markup attribute for HTML.
  • A React component that renders the markup using the HtmlFragment component.

This workaround is temporary. It is replaced by Site-Wide Regions for Content Blocks, which is currently in beta. See Manage Content for Site-Wide Regions in Storefront Next with Content Blocks (Beta).

Important

Step 1: Create the Markup Content Component 

Create the markup content in src/components/markup-content/index.tsx.

1import { Component } from "@/lib/decorators/component";
2import { AttributeDefinition } from "@/lib/decorators/attribute-definition";
3import { RegionDefinition } from "@/lib/decorators/region-definition";
4import HtmlFragment from "@/components/html-fragment";
5import type { ComponentType } from "@/components/region";
6
7@Component("markupContent", {
8  name: "Markup Content",
9  description: "Displays HTML markup content - use for reusable content blocks",
10})
11@RegionDefinition([])
12export class MarkupContentMetadata {
13  @AttributeDefinition({ type: "markup", name: "Markup" })
14  markup?: string;
15}
16
17interface MarkupContentProps {
18  markup?: string;
19  component?: ComponentType;
20}
21
22export default function MarkupContent({ markup, component }: MarkupContentProps) {
23  const content = markup || (component?.data?.markup as string) || "";
24
25  if (!content) return null;
26
27  return <HtmlFragment content={content} />;
28}

Step 2: Create the Content Slot Page Type JSON 

Create the content slot page. Add the contentSlotPage.json file in cartridges/app_storefrontnext_base/cartridge/experience/pages/ and add this content.

1{
2  "name": "Content Slot Page",
3  "description": "Minimal page type for reusable content - single content region",
4  "arch_type": "headless",
5  "region_definitions": [
6    {
7      "id": "content",
8      "name": "Content Region",
9      "description": "Add Markup Content components here",
10      "max_components": 5
11    }
12  ],
13  "supported_aspect_types": [],
14  "route": "/content-slot"
15}

Step 3: Create a Preview Route for Page Designer 

Content slot pages need a preview route to be editable in Page Designer’s design mode. Create the _app.content-slot.tsx file in src/routes/_app.content-slot.tsx and add this content.

1import { Region } from "@/components/region";
2import { fetchPageWithComponentData } from "@/lib/util/pageLoader";
3import type { LoaderFunctionArgs } from "react-router";
4
5export function loader(args: LoaderFunctionArgs) {
6  return {
7    // Replace {content-id} with the ID of the page you create in Page Designer
8    page: fetchPageWithComponentData(args, { pageId: "{content-id}" }),
9  };
10}
11
12export default function ContentSlotPreviewPage({ loaderData }) {
13  return (
14    <div className="max-w-7xl mx-auto px-4 py-8">
15      <Region page={loaderData.page} regionId="content" />
16    </div>
17  );
18}

Step 4: Generate and Deploy Metadata 

Use these commands to generate and deploy the metadata.

1pnpm generate:cartridge
2pnpm push
3pnpm sfnext deploy-cartridge

Step 5: Set Up a Content Slot in Business Manager 

To be able to bind content assets to components in Page Designer, turn on a feature switch. In Administration > Global Preferences > Feature Switches, turn on Enable Page Designer Data Binding.

Important

  1. Create a content slot page in Merchant Tools > Content > Page Designer > New Page.
  2. Select Content Slot Page as the page type.
  3. Add Markup Content components to the “content” region.
  4. Configure markup by entering HTML directly or by using data binding to bind to Content Assets.
  5. Assign a page ID (for example, shipping-policy or legal-disclaimer). You reference this ID when fetching the page.

Populate the Content 

You can populate content in two ways.

Option 1: Direct HTML entry 

Enter HTML directly in the Markup field of a Markup Content component. This approach is best for content that is specific to your Storefront Next storefront.

Option 2: Data binding to content assets 

Bind the Markup field to a content asset’s HTML attribute. This approach is best for content that must be shared across multiple storefront technologies (SFRA and Storefront Next). Content assets are platform-agnostic, so you can update content once and have it reflected across all storefronts.

Embed Content in Your Storefront 

Use fetchPageWithComponentData and the Region component to load and render content slot page data anywhere in your storefront.

1import { Region } from "@/components/region";
2import { fetchPageWithComponentData } from "@/lib/util/pageLoader";
3import type { LoaderFunctionArgs } from "react-router";
4
5export function loader(args: LoaderFunctionArgs) {
6  return {
7    basket: fetchBasket(args.context),
8    // Load content slot page data
9    shippingInfo: fetchPageWithComponentData(args, { pageId: "checkout-shipping-info" }),
10  };
11}
12
13export default function CheckoutPage({ loaderData }) {
14  return (
15    <div>
16      <h1>Checkout</h1>
17      {/* Your page content */}
18
19      {/* Embedded content from Page Designer */}
20      <aside className="mt-8">
21        <Region page={loaderData.shippingInfo} regionId="content" />
22      </aside>
23    </div>
24  );
25}

Content updates in Business Manager are reflected immediately without code changes.

Content Slot Workaround Limitations 

  • No dedicated APIs for content slot management—uses the same fetchPageWithComponentData as regular pages.
  • No caching or CDN strategies specific to embedded content.
  • Merchants must navigate to Page Designer to edit content—no inline editing where it’s embedded.
  • You must create a “page” in Business Manager for content that isn’t actually a full page.

When the “Embedded Content” feature ships, migrate your content slot pages to the new system and update component references to the new API.

Quick Reference 

Component Checklist 

  • @Component decorator with id, name, group, description
  • @AttributeDefinition for each configurable prop
  • @RegionDefinition if component contains nested regions
  • export function fallback() - lightweight loading state
  • export default - main component
  • export const loader - if data loading needed

Page Checklist 

  • @PageType decorator with name, description, supportedAspectTypes
  • @RegionDefinition for each region in the page
  • export class [Name]Metadata {} - metadata class
  • <Region> components with matching regionId

Commands 

CommandPurpose
pnpm buildBuild the app and generate cartridge.
pnpm generate:cartridgeGenerate cartridge metadata only.
pnpm pushDeploy cartridge to MRT and B2C Commerce.