Mon May 30 2022
Example React component to render Contentful Rich Text
A quick code snippet showcasing how I render the rich text I get from a Contentful CMS
This isn't a how-to-do XYZ kind of blog post, but more of a post where I want to show how I created my own component to render Rich Text from a Contentful CMS using GraphQL.
So here is the code
1import Image from "next/image";2import { documentToReactComponents } from "@contentful/rich-text-react-renderer";3import {4 BLOCKS,5 MARKS,6 INLINES,7 Hyperlink,8 AssetLinkBlock,9 Paragraph,10} from "@contentful/rich-text-types";11import CodeRenderer from "./CodeRenderer";12import Link from "next/link";13import { RichTextRendererProps } from "../../singleBlogPostPage/interfaces";14import {15 RichTextContent,16 SideBar,17} from "../../singleBlogPostPage/SingleBlogPostPageStyles";18import { NEW_ASSET } from "../interfaces";19import PostPill from "../PostPill/PostPill";20const RichTextRenderer = ({ content }: RichTextRendererProps) => {21 // when rendering urls I first check whether they are external ones or not.22 // if external I render an <a> tag. If internal I use the next/link23 const website_url = "https://kishokanth.com/";24 const { json, links } = content;25 const Options = {26 renderMark: {27 [MARKS.BOLD]: (text: string) => <strong>{text}</strong>,28 [MARKS.ITALIC]: (text: string) => <i>{text}</i>,29 // CodeRenderer is the component which handles the rendering of code.30 [MARKS.CODE]: (text: string) => <CodeRenderer code={text} />,31 },32 renderNode: {33 [BLOCKS.PARAGRAPH]: (node: Paragraph, children: any) => {34 return <p>{children}</p>;35 },36 [BLOCKS.QUOTE]: (node: Paragraph, children: any) => {37 return <div className="blockQuote">{children}</div>;38 },39 // I chose to not render inline assets inside the rich text as40 // I wanted to use the inline assets in a sidebar to display related posts41 // you can see this in the return statement of this component42 [NEW_ASSET.INLINE_ASSET]: (node: Paragraph, children: any) => {43 return null;44 },45 [BLOCKS.EMBEDDED_ASSET]: (node: AssetLinkBlock) => {46 const image = links?.assets.block.find(47 (i) => i.sys.id === node.data.target.sys.id48 );49 if (image) {50 return (51 <Image52 src={image?.url}53 alt={image?.title}54 layout="responsive"55 width={image?.width}56 height={image?.height}57 />58 );59 }60 return (61 <p>62 <i>63 Ooops, we are having some trouble displaying an image that should64 be here65 </i>66 </p>67 );68 },69 [INLINES.HYPERLINK]: (node: Hyperlink) => {70 const {71 data: { uri },72 content,73 } = node;74 return uri.includes(website_url) ? (75 <Link href={uri}>{content[0].value}</Link>76 ) : (77 <a href={uri} rel="noopener noreferrer" target="_blank">78 {content[0].value}79 </a>80 );81 },82 },83 };84 return (85 <RichTextContent>86 {documentToReactComponents(json, Options)}87 <SideBar>88 <h2>Related Posts</h2>89 {links.entries.inline.map((card) => (90 <PostPill {...card} key={card.slug} />91 ))}92 </SideBar>93 </RichTextContent>94 );95};96export default RichTextRenderer;
Of course, you can customise the above to fit more use cases. In fact, I'd love to see how you customised yours! Do share a link to a gist or your repo!