Skip to content

Latest commit

 

History

History
213 lines (156 loc) · 5.64 KB

File metadata and controls

213 lines (156 loc) · 5.64 KB

Rendering (with React)

In this page you will learn how to create a React component for your content type and how to render it.

Step 1. Create a React component for Article

Open the src/app/components/Article.tsx file and add the following

import { RichText } from '@episerver/cms-sdk/react/richText';

type Props = {
  content: ContentProps<typeof ArticleContentType>;
};

export default function Article({ content }: Props) {
  return (
    <main>
      <h1>{content.heading}</h1>
      <RichText content={content.body?.json} />
    </main>
  );
}

Note

For complete documentation on the RichText component including all props, advanced customization options, fallback handling, and TypeScript support, see the RichText Component Reference.

The entire file should look like this:

import { contentType, ContentProps } from '@optimizely/cms-sdk';
import { RichText } from '@optimizely/cms-sdk/react/richText';

export const ArticleContentType = contentType({
  key: 'Article',
  baseType: '_page',
  properties: {
    heading: {
      type: 'string',
    },
    body: {
      type: 'richText',
    },
  },
});

type Props = {
  content: ContentProps<typeof ArticleContentType>;
};

export default function Article({ content }: Props) {
  return (
    <main>
      <h1>{content.heading}</h1>
      <RichText content={content.body?.json} />
    </main>
  );
}

Step 2. Register the component

Edit the src/app/layout.tsx to register the Article component. Add the following snippet below initContentTypeRegistry():

initReactComponentRegistry({
  resolver: {
    Article,
  },
});

The entire layout.tsx should look like this:

import Article, { ArticleContentType } from '@/components/Article';
import { initContentTypeRegistry } from '@optimizely/cms-sdk';
import { initReactComponentRegistry } from '@optimizely/cms-sdk/react/server';

initContentTypeRegistry([ArticleContentType]);
initReactComponentRegistry({
  resolver: {
    Article,
  },
});

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Step 3. Change the page

Open src/app/[...slug]/page.tsx file and replace the last line inside the Page function:

- return <pre>{JSON.stringify(content[0], null, 2)}</pre>
+ return <OptimizelyComponent content={content[0]} />;

Your entire file should look like this:

import { GraphClient } from '@optimizely/cms-sdk';
import {
  OptimizelyComponent,
  withAppContext,
} from '@optimizely/cms-sdk/react/server';
import React from 'react';

type Props = {
  params: Promise<{
    slug: string[];
  }>;
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};

export async function Page({ params }: Props) {
  const { slug } = await params;

  const client = new GraphClient(process.env.OPTIMIZELY_GRAPH_SINGLE_KEY!, {
    graphUrl: process.env.OPTIMIZELY_GRAPH_GATEWAY,
  });
  const content = await client.getContentByPath(`/${slug.join('/')}/`);

  return <OptimizelyComponent content={content[0]} />;
}

export default withAppContext(Page);

Go again to http://localhost:3000/en. You should see your page

Understanding withAppContext

The withAppContext HOC wraps your page component to provide request-scoped context:

export async function Page({ params }: Props) {
  // ... component logic
}

export default withAppContext(Page);

What it does:

Initializes context storage - Sets up isolated, request-scoped storage for context data. This is required when using the context system in React Server Components.

When do you need it:

Since getPreviewContent automatically populates context with preview data, withAppContext is optional for preview pages. Use it when:

  • You need context initialized before fetching content (e.g., for manual setContextData calls)
  • You're using context for non-preview data
  • You want to ensure context is available throughout the component tree

Benefits:

  • Request isolation - Each request gets its own context storage (critical for server components)
  • No prop drilling - Access context data anywhere in your component tree
  • Framework-agnostic - Works with any React Server Components framework

Accessing Context in Components

Any component can access the context data without props:

import { getContext } from '@optimizely/cms-sdk/react/server';

export function MyComponent() {
  const context = getContext();

  // Access preview token, locale, etc.
  const locale = context?.locale ?? 'en-US';
  const isPreview = !!context?.preview_token;

  return <div>Locale: {locale}</div>;
}

How context is populated:

Context data can be populated in two ways:

  1. Automatically by getPreviewContent - This method automatically sets preview_token, locale, key, version, and ctx in the context
  2. Manually via setContextData() - You can explicitly set context data when needed

This is particularly useful for:

  • Displaying locale-specific formatting
  • Getting content version and key for manual queries and rendering

Next steps

You have finished 🎉!

This is the end of the tutorial on how to create your first website using Optimizely CMS SaaS.

You can continue exploring these topics:

  • Add Experiences - Learn how to create personalized content experiences for different audiences
  • Add Live Preview - Enable real-time content editing and preview capabilities
  • Add Display Settings - Configure how your content is displayed across different contexts