This content originally appeared on DEV Community and was authored by Aswanth Raveendran EK
Introduction
In modern web development, creating dynamic and scalable websites is essential for delivering personalized user experiences. One of the most effective ways to achieve this is by integrating a headless CMS with a frontend framework like Next.js. A headless CMS allows developers to separate the content management layer from the presentation layer, enabling seamless content updates without touching the codebase. This setup is ideal for sites that require frequent content changes, like blogs, portfolios, and e-commerce sites.
The Role of Headless CMS
A headless CMS (Content Management System) is a backend-only system that manages content independently of the frontend. This approach allows developers to select or build a frontend framework without being constrained by the CMS’s native capabilities. Popular headless CMS options includes Strapi, Payload etc.
With a headless CMS, content creators and developers can work in parallel: editors manage content, and developers focus on the presentation layer using tools like Next.js.
NB: You don't need to know more about CMS to create this. Just understand about the APIs your CMS framework provides.
Set Up
Create a component called renderBlocks in your Next JS src folder.
Now create a functional component
import type { Page } from "@/types/block-types/types";
import React, { Fragment } from "react";
import HeroBanner from "./blocks/HeroBanner";
import FormBlock from "./blocks/FormBlock";
const blockComponents = {
banner: HeroBanner,
formBlock: FormBlock
};
interface RenderBlocksProps {
blocks: Page["layout"];
}
export const RenderBlocks: React.FC<RenderBlocksProps> = (props) => {
};
The blockComponents object contain the Components that we created in our project.
The component will accept a prop called blocks which is the API response of the CMS which includes all the data that needs to show in the page.
Below is an example type of blocks
export interface Page {
layout: (BannerBlock | FormBlock)[];
}
export interface BannerBlock {
media: {
src: string;
alt: string;
};
title: string;
blockType: "banner"
}
export interface FormBlock {
title: string;
blockType: "formblock"
}
You can create a file called block-types.ts in the utils folder and create your types for blocks there.
NB: This types can be changed according to the CMS you use and also it depends on the field name that you use in your CMS.
In the blocks props you will have array of objects each object is the data that you want to show in your page. And each object contain a unique property. I mentioned it here as blockType. This blockType should be the same key of the blockComponents object.
Below is a mock data that you are going to get from your CMS API. This will have changes from an actual response. I am just showing it here for better understanding.
{
layout: [
{
image: {
src: "image.png",
alt: "Alt text",
},
title: "Banner Title",
blockType: "banner",
},
{
title: "Contact Form",
blockType: "formBlock"
}
]
};
Below is the complete code for your renderBlocks component
import type { Page } from "@/types/block-types/types";
import React, { Fragment } from "react";
import HeroBanner from "./blocks/HeroBanner";
import FormBlock from "./blocks/FormBlock";
const blockComponents = {
banner: HeroBanner,
formBlock: FormBlock
};
interface RenderBlocksProps {
blocks: Page["layout"];
}
export const RenderBlocks: React.FC<RenderBlocksProps> = (props) => {
const { blocks } = props;
const hasBlocks = blocks && Array.isArray(blocks) && blocks.length > 0;
if (hasBlocks) {
return (
<Fragment>
{blocks.map((block, index) => {
const { blockType } = block;
if (blockType && blockType in blockComponents) {
const Block = blockComponents[blockType];
if (Block) {
return (
<div key={index}>
{/* @ts-expect-error: has no properties in common with type 'IntrinsicAttributes' */}
<Block {...block} />
</div>
);
}
}
return null;
})}
</Fragment>
);
}
return null;
};
How to use this?
Create a page in your app directory and call the render blocks components there with data you fetched from the CMS API.
import { Page } from "@/types/block-types/types";
import { RenderBlocks } from "@/component/RenderBlocks";
const HomePage= async() => {
cons page:Page = await CallToPageDataAPI()
return (
<div className="bg-background">
<RenderBlocks blocks={page.layout} />
</div>
);
};
export default HomePage;
The logic presented here is tailored to my specific use case, but feel free to adapt it as needed. If you encounter any issues or have suggestions, please don't hesitate to leave a comment. I'm always open to feedback and improvement. Thank you for taking the time to read this!
NB: A CMS API response will be more complex than what is referred to here. Please make necessary changes to the types according to your use case.
This content originally appeared on DEV Community and was authored by Aswanth Raveendran EK
Aswanth Raveendran EK | Sciencx (2024-10-26T07:33:58+00:00) Render Block component in Next JS and Headless CMS. Retrieved from https://www.scien.cx/2024/10/26/render-block-component-in-next-js-and-headless-cms/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.