Syntax Highlighting: How to Parse HTML and Highlight Code Blocks in React or Next.js
Posted by: Team Codeframer | @codeframerWhen building a blog, documentation site, or any app that displays rich content fetched from an API, you'll often run into two challenges:
You receive HTML content as a raw string.
You want to parse it into React components.
Plus, you need to highlight any
<code>
blocks beautifully.
In this guide, you'll learn exactly how to do that, step-by-step — the right, production-grade way.
Why Do We Need This?
When your backend sends blog content, it often looks like this:
>_ Html1<h1>Hello World</h1> 2<p>This is a blog post.</p> 3<pre><code class="language-javascript"> 4const greet = (name) => `Hello, ${name}`; 5</code></pre>
The problem?
In React/Next.js, you can't simply inject this HTML safely and expect it to behave properly.
You want:
The
<h1>
and<p>
to render as normal elements.The
<code>
block to be syntax-highlighted beautifully (not just plain text).
Our Final Goal
We want to:
Parse raw HTML into safe React elements.
Detect
<pre><code>
blocks.Replace those with a syntax highlighter component.
Support multiple languages automatically (JavaScript, Python, etc.).
Step 1: Install Required Packages
We'll use two excellent libraries:
>_ Bash1npm install html-react-parser react-syntax-highlighter
What they do:
html-react-parser
: Parses a raw HTML string into React components.react-syntax-highlighter
: Provides beautiful syntax coloring for code blocks.
Step 2: Create the HTML Parser Component
Let's create a flexible and clean React component called ParsedContent.tsx
:
>_ Tsx1'use client'; 2 3import parse, { domToReact, HTMLReactParserOptions, Element } from 'html-react-parser'; 4import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; 5import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; 6 7interface ParsedContentProps { 8 content: string; // Your fetched HTML string 9} 10 11export function ParsedContent({ content }: ParsedContentProps) { 12 const options: HTMLReactParserOptions = { 13 replace: (domNode) => { 14 if (domNode instanceof Element && domNode.name === 'pre') { 15 const codeElement = domNode.children[0] as Element; 16 17 if (codeElement?.name === 'code') { 18 const className = codeElement.attribs.class || ''; 19 const languageMatch = className.match(/language-(\w+)/); 20 const language = languageMatch ? languageMatch[1] : 'text'; 21 22 const code = codeElement.children 23 .map((child) => ('data' in child ? child.data : '')) 24 .join(''); 25 26 return ( 27 <SyntaxHighlighter 28 language={language} 29 style={oneDark} 30 PreTag="div" 31 > 32 {code.trim()} 33 </SyntaxHighlighter> 34 ); 35 } 36 } 37 }, 38 }; 39 40 return <div>{parse(content, options)}</div>; 41}
Step 3: How This Works
html-react-parser
reads the raw HTML.During parsing, it uses the
replace
function:If it finds a
<pre><code>
block:It extracts the text inside.
Detects the programming language from the
class
attribute (language-xxx
).Replaces it with a
<SyntaxHighlighter>
component.
react-syntax-highlighter
then renders the code with gorgeous styling.
Default Theme:
We used the oneDark
theme.
(You can easily switch to others like atomDark
, dracula
, etc.)
Step 4: Usage Example
Here's how you would use the ParsedContent
component inside a page:
>_ Tsx1import { ParsedContent } from './components/ParsedContent'; 2 3export default function BlogPage() { 4 const content = ` 5 <h1>Hello World</h1> 6 <p>This is a paragraph.</p> 7 <pre><code class="language-javascript"> 8 const greet = (name) => \`Hello, \${name}\`; 9 </code></pre> 10 `; 11 12 return ( 13 <div className="prose prose-lg mx-auto"> 14 <ParsedContent content={content} /> 15 </div> 16 ); 17}
Result:
The heading (
<h1>
) and paragraph (<p>
) will render normally.The JavaScript code will be automatically syntax-highlighted.
Step 5: (Optional) Improve Styling with Tailwind Typography
If you're using Tailwind CSS, you can make your blog content even more beautiful by adding typography utilities (prose
classes).
But:
The prose
classes only work after you install the Tailwind Typography Plugin.
How to Install Tailwind Typography (Optional)
Install the plugin:
>_ Bash1npm install @tailwindcss/typography
Enable it in your
tailwind.config.js
:
>_ Js1// tailwind.config.js 2module.exports = { 3 content: ['./src/**/*.{js,ts,jsx,tsx}'], 4 theme: { 5 extend: {}, 6 }, 7 plugins: [require('@tailwindcss/typography')], 8};
Use the
prose
classes in your layout:
>_ Tsx1<div className="prose prose-lg mx-auto dark:prose-invert"> 2 <ParsedContent content={content} /> 3</div>
prose
: Beautifies text, headings, paragraphs, lists automatically.dark:prose-invert
: Makes prose work in dark mode too!
Note: This step is completely optional — you can use
ParsedContent
even without Tailwind Typography if you prefer custom styles.
Step 6: Handling Edge Cases (Advanced)
Sometimes, your API might return code blocks without a language-xxx
class.
In that case, we default to 'text'
, which prevents any errors:
>_ Tsx1const language = languageMatch ? languageMatch[1] : 'text';
You could even improve this further by:
Guessing the language based on code content.
Displaying a small warning (e.g., "No language detected").
Full Code Recap
>_ Tsx1'use client'; 2 3import parse, { domToReact, HTMLReactParserOptions, Element } from 'html-react-parser'; 4import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; 5import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; 6 7interface ParsedContentProps { 8 content: string; 9} 10 11export function ParsedContent({ content }: ParsedContentProps) { 12 const options: HTMLReactParserOptions = { 13 replace: (domNode) => { 14 if (domNode instanceof Element && domNode.name === 'pre') { 15 const codeElement = domNode.children[0] as Element; 16 17 if (codeElement?.name === 'code') { 18 const className = codeElement.attribs.class || ''; 19 const languageMatch = className.match(/language-(\w+)/); 20 const language = languageMatch ? languageMatch[1] : 'text'; 21 22 const code = codeElement.children 23 .map((child) => ('data' in child ? child.data : '')) 24 .join(''); 25 26 return ( 27 <SyntaxHighlighter 28 language={language} 29 style={oneDark} 30 PreTag="div" 31 > 32 {code.trim()} 33 </SyntaxHighlighter> 34 ); 35 } 36 } 37 }, 38 }; 39 40 return <div>{parse(content, options)}</div>; 41}
Conclusion
By following this approach, you can safely parse HTML into real React components and beautifully highlight code blocks in your frontend apps.
This method is lightweight, production-ready, and used by major blogging platforms.
Now you’re ready to build dynamic blogs, documentation sites, or CMS apps with complete control over styling and rendering!