React hydration errors in Next.js can be frustrating especially when you are building a blog page using the WordPress REST API and rendering HTML content like excerpt.rendered.
If you’re seeing errors like:
- Hydration failed because the initial UI does not match what was rendered on the server
- Text content does not match server-rendered HTML
- Expected server HTML to contain a matching
don’t worry. This guide explains why it happens and provides a complete working fix for WordPress + Next.js.
What is a Hydration Error in Next.js?
Next.js renders your page in two steps:
- Server-Side Rendering (SSR): HTML is generated on the server.
- Client Hydration: React runs in the browser and attaches event handlers to the existing HTML.
A hydration error happens when:
The server renders one HTML structure
But the browser React render produces something slightly different
Even one small difference like an extra <p>, whitespace, or a different tag structure can trigger hydration problems.
Why This Happens with WordPress REST API Content
WordPress often returns HTML inside fields such as:
title.renderedexcerpt.renderedcontent.rendered
Example excerpt coming from WP API:
<p>If you have heard that there are ways to make money while shopping in the UAE and would like...</p>
When you render that using certain parsing methods (like react-html-parser), the server output may differ from the client output.
Common Causes of Hydration Error in Your Setup
Using react-html-parser in SSR:
Libraries like react-html-parser can produce different results in Node.js (server) vs browser (client), causing mismatched markup.
Invalid HTML nesting:
Your code wraps HTML output inside <p className="expert"> ... </p> but WordPress excerpt already contains <p> tags.
That creates invalid HTML like:
<p class="expert">
<p>WordPress paragraph here</p>
</p>
Browsers “fix” invalid HTML differently than React expects → hydration mismatch.
Using unstable keys (key={i}):
Using index keys can cause React to mismatch elements if data order changes or updates between renders.
Your Original Code (Problem Area)
This line causes the biggest issue:
<p className="expert">{ReactHtmlParser(x.excerpt.rendered)}</p>
Because x.excerpt.rendered already contains <p>...</p> tags.
The Best Fix (Recommended for Next.js + WordPress)
Replace react-html-parser with dangerouslySetInnerHTML
This renders the same HTML string on both server and client, preventing hydration mismatches.
Also: Don’t wrap WP HTML inside <p>
Use a <div> instead.
Final Fixed Code (Complete Working Solution)
import React, { Component } from "react";
import Link from "next/link";
import { BiCalendar } from "react-icons/bi";export default class Blog extends Component {
constructor(props) {
super(props);
this.state = {
data: props.bloglist || [],
};
} render() {
const { data } = this.state;
if (!data || data.length === 0) return null; return (
<div className="container blog-section">
<div className="row">
<h2>Latest Posts</h2>
</div> <div className="row">
{data.map((x) => (
<div className="col-md-4 boxs text-center" key={x.id}>
<div className="bg-info">
<img
src={x?.images?.large}
className="img-fluid"
alt={x?.title?.rendered || "Post image"}
/> <h3>{x?.title?.rendered}</h3> <p className="shopping">
<span>
<BiCalendar /> {x?.date}
</span>
</p> {/* FIX: Render WordPress HTML safely without parsing mismatch */}
<div
className="expert"
dangerouslySetInnerHTML={{ __html: x?.excerpt?.rendered || "" }}
/> <Link href={`/blog/${x.slug}/${x.id}`}>
<div className="readmore">
<span>Readmore</span>
</div>
</Link>
</div>
</div>
))}
</div>
</div>
);
}
}
Why This Fix Works
dangerouslySetInnerHTML renders the same HTML string on the server and client
avoids SSR vs browser parsing differences
no invalid nested <p> tags
stable React keys (key={x.id})
Bonus: Make It More Secure (Highly Recommended)
Because WordPress content can contain unwanted HTML, you should sanitize it.
A common option is sanitize-html.
Install:
npm install sanitize-html
Use:
import sanitizeHtml from "sanitize-html";const cleanHTML = sanitizeHtml(x?.excerpt?.rendered || "", {
allowedTags: sanitizeHtml.defaults.allowedTags,
allowedAttributes: {
a: ["href", "target", "rel"],
img: ["src", "alt"],
},
});
Then:
<div dangerouslySetInnerHTML={{ __html: cleanHTML }} />
Conclusion
If you’re using WordPress REST API in Next.js and rendering excerpt.rendered, hydration errors usually come from invalid HTML nesting and differences between server and client parsing.

