Rendering CMS Rich Text Safely in Gatsby and React

CMS rich text is not the same thing as a safe blob of HTML.
In Contentful and similar CMSes, rich text is structured data. It represents paragraphs, headings, lists, links, embedded entries, assets, and marks. Gatsby and React then need to decide how those nodes become components.
That decision is where a lot of front‑end quality lives.
Map Nodes Deliberately
Do not treat rich text rendering as a one‑line utility that gets forgotten.
Decide how to render:
- paragraphs
- headings
- unordered lists
- ordered lists
- links
- embedded assets
- embedded entries
- code blocks
- quotes
The Contentful rich text documentation explains the structure. The front‑end job is to map that structure to the project's HTML and React components.
Keep Heading Levels Under Control
Rich text fields can create heading problems if editors can choose any level anywhere.
An article title may already be the page h1. Rich text headings should then usually start below that. If an editor inserts another h1 inside the body, the document structure becomes less clear.
The renderer can enforce or normalise heading rules, but the CMS model and editorial guidance should help too. Do not make the renderer responsible for silently fixing every content problem.
Render Links with Care
Links in rich text need different treatment depending on their type:
- external URL
- internal entry link
- asset link
- email link
- anchor link
For internal entries, prefer resolving the entry to a real site URL rather than leaving CMS IDs in front‑end code. For external links, decide how to handle target, rel, and visible link text.
Broken references should fail clearly during build or render a safe fallback. A missing linked entry should not produce an empty anchor.
Treat Embedded Entries as Components
Embedded entries are where rich text becomes more than formatted copy.
They might represent:
- code snippets
- callouts
- image blocks
- video embeds
- related articles
- product cards
The article on rendering Contentful Rich Code snippets in Gatsby is one example. A code snippet entry needs syntax, language, caption, and safe markup. It should not be treated like an ordinary paragraph.
Avoid Unsafe HTML Shortcuts
React makes it possible to inject HTML directly, but rich text usually gives you a safer option: render known nodes to known components.
Avoid bypassing that structure unless there is a strong reason. Direct HTML injection raises questions about sanitisation, allowed tags, and editor permissions.
Structured rich text is useful precisely because the front‑end renderer can control what each node type becomes.
Test Awkward Content
Rich text renderers need real test cases:
- nested lists
- empty paragraphs
- long links
- embedded entries in lists
- missing embedded assets
- code blocks
- bold and italic marks
- internal entry links
- unsupported node types
These are the kinds of small rendering issues that only appear when real rich text is involved. A renderer that works for three neat paragraphs has not really been tested yet.
Rich text rules also affect preview and migration work. Planning content models for a headless CMS covers the modelling side, and fixing Contentful preview in Next.js Draft Mode covers the later preview problem in a Next.js workflow.
Wrapping Up
Rendering CMS rich text safely is about keeping control of the translation from content model to front‑end output.
Map nodes explicitly, handle links and embeds carefully, avoid unsafe shortcuts, and test the messy cases. Rich text is powerful when it gives editors flexibility without making the rendered page unpredictable.
Key Takeaways
- CMS rich text should be rendered through explicit node mappings.
- Heading levels need rules that fit the surrounding page template.
- Internal and external links need different rendering decisions.
- Embedded entries should become deliberate React components.
- Test nested, missing, unsupported, and awkward rich text cases.