The HTML Sanitizer API
The HTML Sanitizer API
07 May 2026
There are three ways an engineer learns about Cross-Site Scripting (XSS).
The lucky ones learn about it through a helpful code review or a proactive security lint rule. The diligent ones learn about it during a security audit that catches a vulnerability before it hits production.
Then, there are the scarred ones . They learn about it when a live exploit hits their site. When an attacker injects a script that steals session tokens from localStorage, hijacks cookies, or redirects users to a phishing site. I personally joined the “scarred” club back in 2005, when an embedded Flash signature in a forum I owned turned into a security nightmare… but that’s a story for another time.
In this article, we’re going to explore how the browser is finally taking the burden of sanitization off our shoulders with the new HTML Sanitizer API .
The Problem with innerHTML
To understand the solution, we have to look at the danger. In the early days of the web, innerHTML was the magic wand that turned strings into DOM elements.
const container = document.getElementById('content');<br>const userInput = '';<br>container.innerHTML = userInput;
The moment that code runs, the browser tries to load a non-existent image, fails, and executes the onerror script. Congratulations, you’ve just been XSS’d.
The snippet above is a classic example of how unsanitized user input can lead to XSS vulnerabilities. Attackers usually ship payloads like this through several vectors:
User-generated content : Comments, reviews, or any form of user input that gets rendered on the page. Usually, these inputs are stored in a database and rendered later. If the application doesn’t sanitize this input, it can lead to stored XSS vulnerabilities.
URL parameters : Attackers can craft URLs with malicious payloads in query parameters. If the application reflects these parameters back into the page without proper sanitization, it can lead to reflected XSS vulnerabilities. For example, a search page that takes a query parameter and displays it on the page without sanitization can be exploited.
Historically, we solved this by pulling in DOMPurify . It’s the de facto library for sanitizing HTML in JavaScript. It works by parsing the input string, removing any dangerous elements or attributes, and returning a safe version of the HTML.
import DOMPurify from 'dompurify';
const container = document.getElementById('content');<br>const userInput = '';<br>const sanitizedInput = DOMPurify.sanitize(userInput);
container.innerHTML = sanitizedInput;
Or if you were using React, you might have done something like the following, using dangerouslySetInnerHTML to render sanitized content:
import DOMPurify from 'dompurify';
function Comment({ content }) {<br>const sanitizedContent = DOMPurify.sanitize(content);<br>return ;
DOMPurify is a fantastic tool that excels at sanitization, but not without caveats. It ships ~23.3 kB minified (~8.71 kB gzipped), requires maintenance, and essentially repeats parsing HTML which is what the browser is already designed to do.
That last point is critical. DOMPurify-style libraries have always been a fragile approach. The parsing APIs exposed to the web don’t always map cleanly to how the browser actually renders a string as HTML in the “real” DOM. Worse, these libraries have to chase the browser’s evolving behavior over time because things that were once safe can turn into time-bombs the moment a new platform feature ships. That puts the maintainers in a permanent race against every browser release, and once a library reaches the size and reach of DOMPurify, that race turns into a full-time job. I imagine the maintainers will be quietly thrilled the day they get to wind it down. The browser, on the other hand, knows exactly when and how it’s going to execute code. Putting sanitization inside the browser means it stays in sync with the parser by definition.
The new HTML Sanitizer API
The web platform now includes new APIs that make parsing and sanitizing HTML much safer. The spec introduces safer ways to insert HTML into the DOM, beyond the old innerHTML approach.
The API gives us six methods, split into two families:
Safe methods : Element.setHTML(), ShadowRoot.setHTML(), Document.parseHTML(). These always strip XSS-unsafe content, no matter what configuration you pass.
Unsafe methods : Element.setHTMLUnsafe(), ShadowRoot.setHTMLUnsafe(), Document.parseHTMLUnsafe(). These do exactly what you tell them to, including allowing dangerous content if your config says so.
Let’s walk through them.
setHTML: The Safe Way to Insert HTML
The setHTML method is a new addition to the DOM API that allows developers to set HTML content in a way that is safe from XSS vulnerabilities. When you use setHTML, the browser automatically sanitizes the input, removing any potentially dangerous elements or attributes. It is safe by default. You still can configure it, but any configuration you pass will...