In React, anything you insert into JSX using {`{ }`} is automatically escaped before it reaches the browser. This protects your UI from malicious HTML or scripts and is a key defense against Cross-Site Scripting (XSS) attacks.
<, >, and & into harmless text.dangerouslySetInnerHTML: A React escape hatch to insert raw HTML into the DOM.JSX automatically escapes values before rendering them in the DOM. Any value embedded inside {`{ }`} is converted into a safe string so that malicious HTML or scripts are treated as plain text instead of executable code.
This is one of React’s built-in security features — it helps protect your app from Cross-Site Scripting (XSS) attacks by default.
Here’s a potentially dangerous string that looks like it could run JavaScript when rendered:
// JSX will safely escape this string before rendering it into the DOM
const userInput = "<img src='x' onerror='alert(1)' />";
function App() {
return <div>User input: {userInput}</div>;
}
React will render the above safely as plain text:
// What the user actually sees on the page
User input: <img src='x' onerror='alert(1)' />
The image tag is not executed as real HTML. React converts special characters like <, >, and & into harmless text before rendering, so the JavaScript inside never runs.
Sometimes you need to display HTML from a trusted source — for example:
React provides a special property called dangerouslySetInnerHTML for this purpose.
// Rendering trusted HTML as real DOM elements instead of plain text
function SafeHTMLExample() {
const htmlData = "<strong>Bold Text</strong> and <em>Italic</em>";
return (
<div dangerouslySetInnerHTML={{ __html: htmlData }} />
);
}
This tells React to insert HTML directly into the DOM. It’s called “dangerous” because it bypasses React’s automatic escaping — use it only when absolutely necessary and only with data you trust.
If you must render user-generated HTML, always sanitize it first before using dangerouslySetInnerHTML. Popular libraries include:
// Using DOMPurify to sanitize user-provided HTML before rendering
import DOMPurify from "dompurify";
function SafeRender({ content }) {
const cleanHTML = DOMPurify.sanitize(content);
return <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />;
}
This pattern lets you safely display HTML coming from users or external APIs while minimizing XSS risk.
When you run the escaping example:
<img src='x' onerror='alert(1)' />.When you use dangerouslySetInnerHTML with the same string without sanitization:
<img> element.onerror handler can execute JavaScript — this is where XSS happens.When you sanitize first (e.g., with DOMPurify), dangerous attributes like onerror are removed, so even if HTML is rendered, the malicious script cannot run.
{`{ }`} over direct HTML injection.DOMPurify to clean HTML from external APIs or rich-text editors.dangerouslySetInnerHTML with user input or unknown sources.UnsafeDemo that displays a malicious HTML string using {`{ }`} and confirm that React escapes it (no alert should fire).dangerouslySetInnerHTML and observe how the browser now treats it as real HTML.dompurify, sanitize the malicious string, and render it again. Check that dangerous attributes are stripped.Goal: Understand how React automatically escapes JSX content, why inserting raw HTML is risky, and how to safely sanitize data before rendering to prevent XSS attacks.