You want to set the inner HTML of an element in a Next.js application. Some use cases for this include:
With vanilla JavaScript, you can use the innerHTML
Web API. To set the inner HTML in React, you use the dangerouslySetInnerHTML
property, which uses the innerHTML
property under the hood. When you render text in React, it sanitizes it by default. It does not sanitize text rendered using dangerouslySetInnerHTML
.
To use the dangerouslySetInnerHTML
property, pass in an object with a __html
key that has a corresponding string value for the HTML string. The React team made the property like this as a safeguard so that developers would look at documentation before using it. It’s not just passing in an HTML string. The HTML string is parsed into HTML elements:
const rawHTML = "<button>click me</button>"; return <div dangerouslySetInnerHTML={{ __html: rawHTML }} />;
The code above returns an HTML button. As the name suggests, it can be dangerous to set the inner HTML as you may add a XSS vulnerability into your app. This can happen if the HTML comes from content submitted by users or from a third-party source. A script could be added that could access sensitive information or give an attacker unauthorized access to an application. For example:
const rawHTML = `<img src="" onerror="alert('You have been hacked!');" />`; return <div dangerouslySetInnerHTML={{ __html: rawHTML }} />;
The rawHTML
will be rendered, and you’ll see an alert message on your screen that displays: “You have been hacked!“. Note that the <div>
tag is self-closing as the element that uses the dangerouslySetInnerHTML
property should not have children.
Given the XSS risks, how do you use this property safely?
If the HTML string comes from user input or a third-party source, you need to sanitize the input. A popular sanitizer library for HTML is DOMPurify. The library also provides a demo of how DOMPurify works, where you can see how dirty HTML is cleaned by removing dangerous HTML like <script
> tags.
When using DOMPurify with Next.js, you need to take server-side rendering into account. From Next.js version 13, components are server-rendered by default. Components are pre-rendered into HTML on the server before being sent to the client. The way you use DOMPurify with Next.js depends on whether you want to use it on the client side only or if you want to use it on the server as well.
You sanitize your HTML string with DOMPurify by calling the sanitize
method with the HTML string as an argument:
"use client"; import DOMPurify from "dompurify"; export default function ClientComponent() { const rawHTML = `<img src="" onerror="alert('You have been hacked!');" />`; return <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(rawHTML) }} />; }
DOMPurify requires a DOM tree to work. To use it in Next.js, you can use it in a Client Component. Note that Client Components pre-render static HTML on the server. To prevent this pre-rendering, dynamically import the component and set server-side rendering to false so that the import only occurs on the client.
The example code below shows how you can use a wrapper component and dynamic importing to render a client-only component:
import dynamic from "next/dynamic"; const ClientOnlyComponent = dynamic(() => import("./ClientComponent"), { ssr: false, loading: () => <p>Loading...</p>, }); const ClientOnlyComponentWrapper = () => { return <ClientOnlyComponent />; }; export default ClientOnlyComponentWrapper;
If you try to run the DOMPurify
sanitize
method in a component that also runs on the server, you’ll get the following error:
Error: dompurify__WEBPACK_IMPORTED_MODULE_1__.default.sanitize is not a function
This error occurs because DOMPurify
requires a DOM tree to work. There is no DOM tree in the server-side Node environment.
To use DOMPurify on the server, you can use the jsdom
library to create a window
object that you can initialize DOMPurify
with:
import { JSDOM } from "jsdom"; const window = new JSDOM("").window; const DOMPurifyServer = DOMPurify(window); const rawHTML = `<img src="" onerror="alert('You have been hacked!');" />`; return <div dangerouslySetInnerHTML={{ __html: DOMPurifyServer.sanitize(rawHTML) }} />;
Alternatively, you can use the isomorphic-dompurify
library which allows you to easily use DOMPurify
on the client and the server. It uses DOMPurify
and jsdom
as dependencies to achieve this.
Get actionable, code-level insights to resolve Next.js performance bottlenecks and errors.
Run the line of code below to:
Create a free Sentry account
Run the CLI install command to automatically add the Sentry SDK to your project:
npx @sentry/wizard@latest -i nextjs
Start capturing errors and performance issues
Loved by over 4 million developers and more than 90,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.