← Back to Chapters

Escaping and Sanitization in React JSX

⚛️ Escaping and Sanitization in React JSX

? Quick Overview

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.

  • JSX Escaping – React converts values into safe text before rendering.
  • XSS Protection – Prevents injected scripts from running in the browser.
  • Sanitization – Extra safety step when you really must render raw HTML.

? Key Concepts

  • Escaping: Converting special characters like <, >, and & into harmless text.
  • XSS (Cross-Site Scripting): An attack where an attacker injects JavaScript into your page.
  • dangerouslySetInnerHTML: A React escape hatch to insert raw HTML into the DOM.
  • Sanitization: Cleaning/stripping unsafe parts from HTML strings before rendering.

⚛️ What is Escaping in JSX?

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.

? Example: JSX Escaping

Here’s a potentially dangerous string that looks like it could run JavaScript when rendered:

? View Code Example
// 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:

? View Rendered Output 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.

? Why Escaping Matters

  • ✅ Prevents attackers from injecting and executing arbitrary scripts in your app.
  • ✅ Makes user-generated data (comments, posts, reviews) safe to display by default.
  • ✅ Keeps React’s declarative rendering model intact without risky manual DOM manipulation.

⚠️ Rendering Raw HTML with dangerouslySetInnerHTML

Sometimes you need to display HTML from a trusted source — for example:

  • Rendering HTML exported from a CMS or blog editor.
  • Showing preformatted Markdown output.
  • Embedding rich content snippets from your own backend.

React provides a special property called dangerouslySetInnerHTML for this purpose.

? View Code Example
// 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.

? Sanitization Before Rendering

If you must render user-generated HTML, always sanitize it first before using dangerouslySetInnerHTML. Popular libraries include:

? View Code Example
// 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.

? Live Output / Explanation

When you run the escaping example:

  • The browser shows the literal text <img src='x' onerror='alert(1)' />.
  • No alert pops up, and no script runs — the input is treated as plain text.

When you use dangerouslySetInnerHTML with the same string without sanitization:

  • The browser creates a real <img> element.
  • The 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.

? Tips & Best Practices

  • Prefer normal JSX rendering with {`{ }`} over direct HTML injection.
  • Use libraries like DOMPurify to clean HTML from external APIs or rich-text editors.
  • Avoid using dangerouslySetInnerHTML with user input or unknown sources.
  • Always validate and sanitize data on the server as well as on the client.
  • Keep a clear boundary between “trusted HTML” (your own templates) and “untrusted HTML” (user content).

? Try It Yourself

  1. Create a component named UnsafeDemo that displays a malicious HTML string using {`{ }`} and confirm that React escapes it (no alert should fire).
  2. Use the same string with dangerouslySetInnerHTML and observe how the browser now treats it as real HTML.
  3. Install dompurify, sanitize the malicious string, and render it again. Check that dangerous attributes are stripped.
  4. Experiment with different user inputs (links, scripts, images) and verify that your sanitization layer blocks unsafe behavior.

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.