This is an issue I come across every once in a while and it always takes me a couple hours to figure it out.
Replicating the issue
Let's say you have a React.js component that will render a paragraph of text coming from a CMS and that content can have HTML tags in it, like a WYSIWYG editor.
// MyTextComponent.js
function MyTextComponent(props) {
return <p dangerouslySetInnerHTML={{ __html: props.content }} />;
}
// App.js
function App(props) {
return (
<div>
<MyTextComponent content={props.content} />
</div>
);
}
The browser renders what you expect:
However, there's that warning in the console that says:
Warning: Prop `dangerouslySetInnerHTML` did not match. Server: "" Client: "<p>This is my paragraph.</p>"
If you're using Next.js, you will get a nicer error message:
What causes this warning?
On my example, the content passed to the component was <p>This is my paragraph.</p>
which would be fine considering that we are using dangerouslySetInnerHTML
to render the content.
However, the component is already wrapping the content in a <p>
tag which, according to the HTML Spec, should only contain phrasing content.
The spec also says:
Paragraphs are block-level elements, and notably will automatically close if another
Here is a CodePen that illustrates and replicates this condition more clearly:
If you inspect the rendered paragraph, you will see the following:
Which doesn't match what the server rendered <p>This is my paragraph.</p>
.
How to fix it?
One solution is to change the wrapping element to a <div>
instead of a <p>
.
// MyTextComponent.js
function MyTextComponent(props) {
return <div dangerouslySetInnerHTML={{ __html: props.content }} />;
}
The main point is to ensure that the rendered content is valid HTML.