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.

export default function HtmlContent() {
  const content = "<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

export default function Article({ body }) {
  return (
    <article
      dangerouslySetInnerHTML={{ __html: body }}
    />
  );
}

body should contain valid HTML markup as a string.


Example 2: Conditionally render HTML or fallback

export default function Description({ 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

import { useState } from "react";

export default function Preview() {
  const [preview, setPreview] = useState(false);
  const content = "<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:

<div dangerouslySetInnerHTML={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.