Sometimes it is necessary to display an HTML code in React, which comes from an external source or a WYSIWYG editor.
By default, this is not allowed for security reasons, but there are a few ways to bypass this limitation.
In this article, we will learn how to inject HTML code into your React component.
To better understand React's default behaviour, let's try embedding some HTML into the React component:
const html = `
<h1>Heading</h1>
<p>Paragraph</p>
`;
const App = () => (
<div>{html}</div>
);
It seems logical to expect "Heading" and "Paragraph" to be rendered in appropriate tags, but that's not how it works.
React treats html as a string and displays the following:
The reason is simple - we prevent XSS attacks.
Cross-site scripting (XSS) is a type of security vulnerability typically found in web applications. XSS attacks enable attackers to inject client-side scripts into web pages viewed by other users.
To prevent this type of vulnerability, React disallows the rendering of embedded values in JSX by automatically escaping anything that is not explicitly written in the application and converting the embedded value to a string before rendering.
What would have happened if React had allowed it?
// Inject link, clicking which executes a script
// That can access any data on your website
// And sent to attackers
const html = `
<h1>XSS Example</h1>
<a href="javascript:alert(1)">Open Link</a>
`;
const App = () => <div>{html}</div>;
The page would have worked this way:
If attackers run any JavaScript code on your page, they have the ability to read any sensitive data (stored in cookies or local storage) and send it to their servers.
This is exactly why React prevents this situation by default.
HTML elements in React can be given a dangerouslySetInnerHTML prop, which is a replacement for innerHTML and allows rendering HTML strings as their content.
It's called dangerous for a reason - using it exposes you to XSS attack:
const html = `
<h1>Heading</h1>
<p>Paragraph</p>
`;
const App = () => <div dangerouslySetInnerHTML={{ __html: html }} />;
The prop receives an object with __html key.
If you decide to go this route, remember to clean up your HTML before rendering, even if it seems "safe" (it comes from an admin panel or other source you control).
HTML sanitization is the process of examining an HTML document and producing a new HTML document that preserves only whatever tags are designated "safe" and desired.
There are many external libraries for this, such as dompurify, sanitize-html, etc.
Install the library:
yarn add dompurify
Use it for your App component:
import React from "react";
import DOMPurify from "dompurify";
// HTML received from the server
const dirtyHTML = `
<h1>Heading</h1>
<p>Paragraph</p>
`;
// The library allows HTML, SVG and MathML
// We only need HTML
const cleanHTML = DOMPurify.sanitize(dirtyHTML, {
USE_PROFILES: { html: true },
});
// Render sanitized HTML
const App = () => <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />;
Read the documentation to find out which tags are allowed by default and how to allow/disallow specific ones.
One of the best libraries available is html-react-parser. It allows parsing HTML code both in Node.js and in the browser.
Install the library:
yarn add html-react-parser
And add it to our example:
import React from "react";
import DOMPurify from "dompurify";
import parse from "html-react-parser";
// HTML received from the server
const dirtyHTML = `
<h1>Heading</h1>
<p>Paragraph</p>
`;
// The library allows HTML, SVG and MathML
// We only need HTML
const cleanHTML = DOMPurify.sanitize(dirtyHTML, {
USE_PROFILES: { html: true },
});
// Render sanitized HTML
const App = () => <div>{parse(cleanHTML)}</div>;
Important note: Always check whether or not the library automatically sanitizes the HTML code. The library we use does not do this, so we still have to sanitize by ourselves.
Choosing the right approach depends a lot on what you want to do with the HTML you receive.
If you just want to display it to users as is, then you may not need any libraries for it, but just clean it up and display it with the dangerouslySetInnerHTML prop.
However, if you want to replace some of the HTML tags with React components and display them, then an external library that allows you to do that is definitely a good solution.
Example: Replace all div elements with data-report-id with the component that retrieves and displays an actual report.
If you use a library, remember to check if it sanitizes HTML automatically for you.
Parsing HTML code is a common task when building web applications.
Every developer needs to know how to do this in the best and safest way.
In this article, we have learned: