How to Render HTML in React

What you’ll build or solve

You’ll render HTML markup from a string inside a React component.

When this approach works best

Rendering HTML works best when you need to:

  • Display rich text stored in a CMS or database.
  • Render formatted content returned from an API.
  • Inject trusted HTML snippets into a component.

Avoid rendering raw user input directly without first reviewing or sanitizing it. Rendering unsafe HTML can expose your app to security risks.

Prerequisites

  • A React app set up
  • Basic JSX knowledge

Step-by-step instructions

1) Render HTML with dangerouslySetInnerHTML

By default, JSX escapes HTML strings for security. If you pass a string that contains tags, React renders it as plain text.

To render actual HTML markup from a string, use the dangerouslySetInnerHTML prop.

exportdefaultfunctionHtmlContent() {
constcontent="<strong>Hello</strong> world";

return (
<div
dangerouslySetInnerHTML={{ __html:content }}
/>
  );
}

Key points

  • The prop name must be dangerouslySetInnerHTML.
  • It expects an object with a __html property.
  • The value of __html must be a string.

What to look for

  • The object shape must be exactly { __html: content }.
  • You cannot use children and dangerouslySetInnerHTML on the same element.
  • The word “dangerous” is intentional. React will not escape the HTML for you.

Examples you can copy

Example 1: Render CMS article content

JavaScript

exportdefaultfunctionArticle({ body }) {
return (
<article
dangerouslySetInnerHTML={{ __html:body }}
/>
  );
}

body should contain valid HTML markup as a string.


Example 2: Conditionally render HTML or fallback

JavaScript

exportdefaultfunctionDescription({ html }) {
if (!html) {
return<p>No description available.</p>;
  }

return (
<div
dangerouslySetInnerHTML={{ __html:html }}
/>
  );
}

Use normal conditional rendering to decide whether to inject HTML.


Example 3: Toggle between raw text and rendered HTML

JavaScript

import {useState }from"react";

exportdefaultfunctionPreview() {
const [preview,setPreview]=useState(false);
constcontent="<em>Preview content</em>";

return (
<div>
<button
onClick={() =>setPreview((p) =>!p)}
>
        Toggle preview
</button>

      {preview? (
<div
dangerouslySetInnerHTML={{ __html:content }}
/>
      ): (
<div>{content}</div>
      )}
</div>
  );
}

When preview is true, the markup renders as HTML. Otherwise, it displays as plain text.


Common mistakes and how to fix them

Mistake 1: Passing a string instead of an object

What you might do:

<divdangerouslySetInnerHTML={content}/>

Why it breaks:

React expects an object with a __html key.

Fix:

<div
dangerouslySetInnerHTML={{ __html:content }}
/>

Mistake 2: Combining children with dangerouslySetInnerHTML

What you might do:

<div
dangerouslySetInnerHTML={{ __html:content }}
>
  Fallback text
</div>

Why it breaks:

React ignores children when dangerouslySetInnerHTML is used.

Fix: Render conditionally instead.

{content? (
<div
dangerouslySetInnerHTML={{ __html:content }}
/>
): (
<p>No content</p>
)}

Troubleshooting

  • If HTML appears as literal text with angle brackets, confirm you are using dangerouslySetInnerHTML instead of {content}.
  • If nothing renders, check that the string is not null or undefined.
  • If React throws a warning about invalid props, confirm the object format is { __html: value }.
  • If your security scanner flags an issue, review how the HTML string is created and whether it needs sanitization before rendering.

Quick recap

  • JSX escapes HTML strings by default.
  • Use dangerouslySetInnerHTML to render real HTML.
  • Pass an object with a __html property.
  • Do not combine children with dangerouslySetInnerHTML.
  • Treat injected HTML as potentially unsafe and handle it carefully.