Discussion on implementing code blocks in Portable Text with React Syntax Highlighter in Next.js
I can see the issue in your code! The problem is that you're using forEach inside your component function, which doesn't return anything. forEach always returns undefined, so React is complaining that nothing was returned from your render function.
The @portabletext/react library passes the block data directly to your custom component as props, so you don't need to iterate through contentRaw at all. Here's the corrected implementation:
const components = {
types: {
code: ({value}) => {
return (
<SyntaxHighlighter language={value.language} style={nightOwl}>
{value.code}
</SyntaxHighlighter>
);
},
},
};The key changes:
- Accept the
valueprop - This contains your code block data (the object withcode,language,_key, etc.) - Return directly - No need to loop through anything, just return the component
- Access properties from
value- Usevalue.codeandvalue.languageinstead of iterating
The @portabletext/react library automatically handles the iteration through your contentRaw array and calls your custom component for each block that matches the type. When it encounters a block with _type: "code", it will call your code component and pass that specific block as the value prop.
Your component will be called once for each code block in your content, so if you have multiple code blocks in contentRaw, each one will render separately with its own data.
If you want to add the filename property that Sanity's code input supports, you could extend it like this:
const components = {
types: {
code: ({value}) => {
return (
<div>
{value.filename && <div className="code-filename">{value.filename}</div>}
<SyntaxHighlighter language={value.language || 'text'} style={nightOwl}>
{value.code}
</SyntaxHighlighter>
</div>
);
},
},
};This pattern works for any custom type in Portable Text - the component receives the block's data as value, along with other useful props like isInline if you need them. You can learn more about custom serializers and component structure in the Sanity guides.
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.