How Sitecore XM Cloud and Next.js Work Together

A detailed exploration of JSS and dynamic rendering in Sitecore Headless

October 21, 2024

By Sohrab Saboori

How Sitecore XM Cloud and Next.js Work Together

Modern front-end frameworks like React, paired with a robust CMS such as Sitecore XM Cloud, offer businesses the flexibility to create dynamic, scalable web applications. Sitecore JSS (JavaScript Services) bridges the gap between Sitecore’s content management and front-end frameworks like Next.js, enabling seamless dynamic rendering in a headless architecture.

This blog will walk through how Sitecore JSS integrates with Next.js, covering:

  • Adding and mapping a rendering in Sitecore.
  • How JSON data from the Layout Service drives the page structure.
  • Using placeholders in Next.js for rendering content.
  • How the Experience Editor supports inline editing.

Rendering Creation in Sitecore

The integration process starts by creating a rendering in Sitecore, such as a "Hero Banner". This rendering represents a reusable component that will be linked to a React component in the Next.js application.

Each rendering in Sitecore is assigned a Rendering Name, which acts as a unique identifier. This name is essential as it maps directly to a specific React component in Next.js. When a page is rendered, Sitecore uses this Rendering Name to identify which component should be loaded on the front end, ensuring that the correct content and logic are applied.

For example:

  • Rendering Name in Sitecore: "Hero Banner"
  • Corresponding React Component in Next.js: <HeroBanner />

Screenshot showing Hero Banner component name mapping in Sitecore.

This mapping ensures that when the Hero Banner rendering is used in Sitecore, the associated React component is dynamically rendered on the front end with the content supplied by Sitecore.

Component Mapping in Next.js (componentBuilder.ts)

When a new rendering is added in Sitecore, Sitecore JSS automatically updates or generates the componentBuilder.ts file in the /temp folder. This file serves as a registry that maps Sitecore's rendering names (like "HeroBanner") to the corresponding React components in the Next.js app.

How It Works

The componentBuilder.ts file is crucial for linking the renderings defined in Sitecore to the React components in the front end. It uses the components.set() method to associate the Rendering Name from Sitecore with the corresponding React component.

For example, if you have a rendering in Sitecore named Hero Banner, the componentBuilder.ts file might look like this:

\src\temp\componentBuilder.ts
import * as HeroBanner from 'src/components/HeroBanner';
components.set('HeroBanner', HeroBanner);

In this snippet:

  • The HeroBanner component is imported from the src/components folder.
  • The components.set() method links the HeroBanner Rendering Name from Sitecore to the HeroBanner React component in the Next.js app.

This automatic mapping ensures that when Sitecore sends the Hero Banner rendering for a specific page, Next.js can dynamically render the corresponding HeroBanner React component with the correct content.

JSON Data from Sitecore Layout Service

When a page is requested, Sitecore’s Layout Service sends a JSON response containing the layout and content for the page. This JSON includes critical details that drive how the page is dynamically rendered by Next.js.

Requesting a Page

The JSON data sent by the Layout Service includes several key elements:

  • Route: Information about the requested page.
  • Fields: Content fields such as text, images, or other data associated with the renderings.
  • Placeholders: Regions on the page where components are rendered, such as headless-header, headless-main, and headless-footer.
  • Rendering Names: The names of the components that correspond to renderings in Sitecore (e.g., "HeroBanner").

Example of JSON Structure

Below is an example of how the JSON might look when Sitecore responds to a page request, including placeholders and renderings like the Hero Banner:

{
  "placeholders": {
    "headless-header": [
      { "componentName": "HeaderComponent", "fields": { "title": "Welcome Header" } }
    ],
    "headless-main": [
      { "componentName": "HeroBanner", "fields": { "title": "Welcome to Our Site", "image": "/path/to/image.jpg" } }
    ],
    "headless-footer": [
      { "componentName": "FooterComponent", "fields": { "footerText": "Footer Content" } }
    ]
  }
}

JSON data for page layout with Sitecore route details in Next.js app.

In this JSON:

  • The headless-header contains the HeaderComponent, with fields that provide data (like the title).
  • The headless-main contains the HeroBanner rendering, along with fields for the banner's title and image.
  • The headless-footer contains the FooterComponent, which includes a footerText field.

The Next.js app uses this JSON to identify which components to render in each placeholder and what content to pass to those components as props.

You can easily view this JSON data directly in the browser using the following command in the developer console:

JSON.parse(document.getElementById("__NEXT_DATA__").textContent)

This command retrieves the __NEXT_DATA__ script tag, which Next.js uses to pass the initial data to the client, and parses it into a readable JSON object. This can help you inspect the placeholders, component names, and fields sent by Sitecore.

Placeholders in Next.js Layout

In Sitecore, placeholders are defined as regions where components can be dynamically inserted. These placeholders correspond to specific areas on the page, such as the header, main content, and footer. When using Sitecore JSS with Next.js, these placeholders are mapped to React components, allowing Sitecore to dynamically determine which components should be rendered in each region.

In Next.js, placeholders are rendered using the Placeholder component provided by the Sitecore JSS SDK. This component allows Next.js to look up the placeholder name (such as headless-header, headless-main, or headless-footer) and render the appropriate components in those regions based on the JSON data sent by Sitecore.

Here’s an example of how placeholders are used in the layout of a Next.js application:

 \src\rendering\src\Layout.tsx
  <div data-template={templateName} className={mainClassPageEditing}>
        <header>
          <div id="header">{route && <Placeholder name="headless-header" rendering={route} />}</div>
        </header>
        <main>
          <div id="content">{route && <Placeholder name="headless-main" rendering={route} />}</div>
        </main>
        <footer>
          <div id="footer">{route && <Placeholder name="headless-footer" rendering={route} />}</div>
        </footer>
      </div>

in this example:

  • The headless-header placeholder will render components such as the site's header.
  • The headless-main placeholder will render main content components like the HeroBanner.
  • The headless-footer placeholder will render components like the site's footer.

React Component Rendering

Once a placeholder is found in the JSON data, the component name associated with that placeholder is used to determine which React component to render. This lookup happens via the componentBuilder.ts file, which maps component names (from the JSON) to their corresponding React components in the Next.js app.

For example, if the HeroBanner rendering is included in the headless-main placeholder, the JSON will specify the componentName as "HeroBanner". Next.js uses componentBuilder.ts to map the "HeroBanner" name to the HeroBanner React component.

Here’s how this mapping looks in the componentBuilder.ts file:

import * as HeroBanner from 'src/components/HeroBanner';
components.set('HeroBanner', HeroBanner);

When Next.js encounters "HeroBanner" in the JSON, it will use the HeroBanner component from the src/components folder.

{
  "placeholders": {
    "headless-main": [
      {
        "componentName": "HeroBanner",
        "fields": {
          "title": "Welcome to Our Site",
          "image": "/path/to/image.jpg"
        }
      }
    ]
  }
}

JSON structure showing HeroBanner and AlertBanner components with their data sources and parameters.

Once Next.js looks up the componentName ("HeroBanner"), it renders the corresponding React component and passes the content fields (like title and image) as props.

Here’s how the HeroBanner component might look when receiving these props:

const HeroBanner = ({ fields }) => (
  <div>
    <h1>{fields.title}</h1>
    <img src={fields.image} alt={fields.title} />
  </div>
);

In this case:

  • The title and image fields are passed from the JSON data provided by Sitecore, allowing the HeroBanner component to dynamically render with the correct content.

Experience Editor Considerations

When you're working in Sitecore's Experience Editor, Sitecore JSS automatically sends additional metadata to the front-end to enable inline editing for content authors. This metadata is critical for allowing users to edit content directly on the page without navigating away from the front-end interface.

In Experience Editor mode, Sitecore JSS wraps components with the necessary metadata that signals which fields can be edited. This is typically handled by a utility like withExperienceEditorChromes, which adds the required editing capabilities around components. The metadata indicates the fields that are editable and injects the correct HTML markup to allow for inline editing.

When in edit mode, the fields sent by Sitecore will contain both the raw values and the editable HTML markup. Here's what the metadata might look like in the JSON response:

Sitecore JSON structure for Hero Banner component fields and data source.

{
  "componentName": "HeroBanner",
  "fields": {
    "title": {
      "value": "Welcome to Our Site",
      "editable": "<span class='scEditableField' data-sc-id='12345'>Welcome to Our Site</span>"
    },
    "image": {
      "value": "/path/to/image.jpg",
      "editable": "<img src='/path/to/image.jpg' class='scEditableField' data-sc-id='67890' />"
    }
  }
}

This ensures that content editors can modify the content directly on the page while in Experience Editor, and the fields are displayed normally when viewed outside of editing mode.

Key Takeaways on Integrating Sitecore XM Cloud with Next.js

In this blog, we explored how Sitecore JSS and Next.js work together in a headless architecture. Here’s a summary of the key steps:

  • Creating renderings in Sitecore: Each rendering is assigned a Rendering Name that corresponds to a React component in Next.js.
  • Automatically map components using componentBuilder.ts: Sitecore JSS dynamically maps the rendering names to the appropriate React components.
  • Use Sitecore Layout Service to send JSON data to Next.js: The Layout Service provides the structure and content of the page, including placeholders and fields.
  • Dynamically render components based on placeholders: Next.js uses placeholders to insert components into the appropriate regions of the page based on the JSON data.
  • Handle inline editing using metadata sent by Sitecore for the Experience Editor: Inline editing is enabled by metadata sent in the JSON, allowing content authors to modify fields directly on the page.

Knowing these steps and understanding this process is highly beneficial for any Sitecore developer, especially when it comes to debugging and optimizing the integration between Sitecore and Next.js. By gaining a deeper understanding of how content is rendered and how inline editing works, developers can better troubleshoot issues, improve performance, and ensure a smooth content management experience for users.

References

Sohrab

Sohrab Saboori

Senior Full-Stack Developer

Sohrab is a Senior Front-End Developer with extensive experience in React, Next.js, JavaScript, and TypeScript. Sohrab is committed to delivering outstanding digital solutions that not only meet but exceed clients' expectations. His expertise in building scalable and efficient web applications, responsive websites, and e-commerce platforms is unparalleled. Sohrab has a keen eye for detail and a passion for creating seamless user experiences. He is a problem-solver at heart and enjoys working with clients to find innovative solutions to their digital needs. When he's not coding, you can find him lifting weights at the gym, pounding the pavement on the run, exploring the great outdoors, or trying new restaurants and cuisines. Sohrab believes in a healthy and balanced lifestyle and finds that these activities help fuel his creativity and problem-solving skills.