---
schema_version: "1"
id: 019702c31a0fcfe215cb1c8f03bdaf8e8ae72806aac502636158265c9ebfadde
title: Migrate Content Slots from SFRA to Storefront Next
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/commerce-cloud/sfnext/guides/sfnext-page-designer-content-slots.md
canonical_url: https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/sfnext-page-designer-content-slots.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: cc86eb6b857335fd9902d42f0e415b634561fc2c924b5c4dbef9844605e1cb04
products:
  - Composable Storefront
  - Salesforce APIs
---
# 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.

**important:** 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)](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/sfnext-page-designer-content-blocks.md).

## Step 1: Create the Markup Content Component

Create the markup content in `src/components/markup-content/index.tsx`.

```tsx
import { Component } from "@/lib/decorators/component";
import { AttributeDefinition } from "@/lib/decorators/attribute-definition";
import { RegionDefinition } from "@/lib/decorators/region-definition";
import HtmlFragment from "@/components/html-fragment";
import type { ComponentType } from "@/components/region";

@Component("markupContent", {
  name: "Markup Content",
  description: "Displays HTML markup content - use for reusable content blocks",
})
@RegionDefinition([])
export class MarkupContentMetadata {
  @AttributeDefinition({ type: "markup", name: "Markup" })
  markup?: string;
}

interface MarkupContentProps {
  markup?: string;
  component?: ComponentType;
}

export default function MarkupContent({ markup, component }: MarkupContentProps) {
  const content = markup || (component?.data?.markup as string) || "";

  if (!content) return null;

  return <HtmlFragment content={content} />;
}
```

## 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.

```json
{
  "name": "Content Slot Page",
  "description": "Minimal page type for reusable content - single content region",
  "arch_type": "headless",
  "region_definitions": [
    {
      "id": "content",
      "name": "Content Region",
      "description": "Add Markup Content components here",
      "max_components": 5
    }
  ],
  "supported_aspect_types": [],
  "route": "/content-slot"
}
```

## 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.

```tsx
import { Region } from "@/components/region";
import { fetchPageWithComponentData } from "@/lib/util/pageLoader";
import type { LoaderFunctionArgs } from "react-router";

export function loader(args: LoaderFunctionArgs) {
  return {
    // Replace {content-id} with the ID of the page you create in Page Designer
    page: fetchPageWithComponentData(args, { pageId: "{content-id}" }),
  };
}

export default function ContentSlotPreviewPage({ loaderData }) {
  return (
    <div className="max-w-7xl mx-auto px-4 py-8">
      <Region page={loaderData.page} regionId="content" />
    </div>
  );
}
```

## Step 4: Generate and Deploy Metadata

Use these commands to generate and deploy the metadata.

```bash
pnpm cartridge:generate
pnpm push
pnpm cartridge:deploy
```

## Step 5: Set Up a Content Slot in Business Manager

**important:** 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**.

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.

```tsx
import { Region } from "@/components/region";
import { fetchPageWithComponentData } from "@/lib/util/pageLoader";
import type { LoaderFunctionArgs } from "react-router";

export function loader(args: LoaderFunctionArgs) {
  return {
    basket: fetchBasket(args.context),
    // Load content slot page data
    shippingInfo: fetchPageWithComponentData(args, { pageId: "checkout-shipping-info" }),
  };
}

export default function CheckoutPage({ loaderData }) {
  return (
    <div>
      <h1>Checkout</h1>
      {/* Your page content */}

      {/* Embedded content from Page Designer */}
      <aside className="mt-8">
        <Region page={loaderData.shippingInfo} regionId="content" />
      </aside>
    </div>
  );
}
```

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

| Command                   | Purpose                                   |
| ------------------------- | ----------------------------------------- |
| `pnpm build`              | Build the app and generate cartridge.     |
| `pnpm cartridge:generate` | Generate cartridge metadata only.         |
| `pnpm push`               | Deploy cartridge to MRT and B2C Commerce. |
