Back

A First Look at the HTML Sanitizer API

A First Look at the HTML Sanitizer API

If you’ve ever used innerHTML to render user-generated content, you’ve accepted some level of XSS risk. The usual fix is pulling in a library like DOMPurify to sanitize the string first. That works, but it means shipping extra JavaScript and trusting a third party to stay ahead of the browser’s evolving parser behavior. The HTML Sanitizer API is the browser’s answer to this problem—and it’s worth understanding now, even if it’s not ready for production use everywhere.

Key Takeaways

  • innerHTML parses and injects markup without any safety checks, making it a persistent XSS vector when handling user-generated content.
  • The HTML Sanitizer API introduces safe methods like Element.setHTML() that automatically strip scripts, event handlers, and dangerous URLs before inserting content into the DOM.
  • You can configure the Sanitizer with allow or remove lists to control exactly which elements and attributes survive sanitization.
  • Browser support is still limited as of early 2026, so production code should use feature detection and fall back to DOMPurify.

Why innerHTML Has Always Been a Risk

innerHTML does exactly what you ask: it parses a string and injects the result into the DOM, no questions asked. That’s convenient until someone passes in <img src=x onerror="stealCookies()"> as a comment or username.

Libraries like DOMPurify address this by parsing the string themselves, walking the resulting DOM tree, and stripping anything dangerous before handing it back to you. It’s effective, but fragile. Browser parsing behavior changes over time, and a library that lives in userspace has to constantly chase those changes. The browser itself, by contrast, always knows exactly how it will parse and execute a given piece of markup.

What the HTML Sanitizer API Provides

The native HTML Sanitizer API moves sanitization into the browser. Instead of setting innerHTML directly, you use new methods that parse, sanitize, and inject in one step.

The safe methods are the ones you’ll reach for most often:

  • Element.setHTML()
  • ShadowRoot.setHTML()
  • Document.parseHTML()

These always strip XSS-unsafe content—<script> tags, event handler attributes like onclick, javascript: URLs in navigation attributes—regardless of what configuration you pass. With no configuration at all, setHTML() is essentially a drop-in replacement for innerHTML with automatic XSS protection:

const userContent = `<p>Hello!</p><script>alert('xss')<\/script>`;
document.getElementById("output").setHTML(userContent);
// Renders: <p>Hello!</p>
// The <script> is silently dropped

The unsafe methodssetHTMLUnsafe(), ShadowRoot.setHTMLUnsafe(), and Document.parseHTMLUnsafe()—give you more control. They apply only the sanitizer configuration you provide, without enforcing the XSS-safe baseline. Use these only when you have a specific reason to allow elements or attributes that the safe methods would block, and only with a carefully constructed configuration.

Configuring the Sanitizer

Both method families accept an optional Sanitizer instance or a configuration dictionary. You can build an allow configuration (specify exactly what’s permitted, drop everything else) or a remove configuration (specify what to strip, allow everything else).

An allow configuration is generally the safer choice:

const sanitizer = new Sanitizer({
  elements: ["p", "b", "em", "a"],
  attributes: ["href"]
});

document.getElementById("comments").setHTML(untrustedInput, { sanitizer });

The Sanitizer class also exposes methods like allowElement() and removeElement() for modifying configurations programmatically while keeping them internally consistent.

Browser Support and What to Do About It

Here’s the honest picture: as of early 2026, the HTML Sanitizer API has only just begun shipping in browsers. Firefox 148 added support, and Chrome 146 followed, but broad cross-browser availability is still catching up. It is not yet part of the Baseline web platform, meaning you cannot rely on it being available for all your users today. You can keep an eye on current support on Can I Use.

For production code, use feature detection and fall back to DOMPurify:

if (typeof Element.prototype.setHTML === "function") {
  element.setHTML(untrustedHTML);
} else {
  element.innerHTML = DOMPurify.sanitize(untrustedHTML);
}

Conclusion

The HTML Sanitizer API represents exactly the kind of thing browser standards should do: take a dangerous, widely mishandled pattern and make the safe path the easy path. setHTML() versus innerHTML isn’t really a debate yet—browser support makes that decision for you. But understanding the API now means you’ll be ready to adopt it as support broadens, and you’ll have a clearer picture of what browser-native HTML sanitization is actually designed to do.

FAQs

Not reliably. As of early 2026, Firefox and Chrome have shipped support, but the API is still a limited-availability feature and not part of the Baseline web platform. For production applications, use feature detection to check for Element.prototype.setHTML and fall back to a library like DOMPurify when the API is unavailable. This gives you native sanitization where supported while maintaining safety everywhere else.

setHTML always enforces a baseline XSS-safe policy. It strips script tags, event handler attributes, and dangerous URLs regardless of your configuration. setHTMLUnsafe applies only the sanitizer configuration you provide without that safety net. Use setHTMLUnsafe only when you explicitly need to allow elements or attributes that the safe method would block.

Not yet. DOMPurify remains necessary as a fallback for browsers that lack Sanitizer API support. Even once browser coverage is universal, DOMPurify offers more granular configuration options that some projects may need. Over time, though, the native API should handle the majority of sanitization use cases without requiring a third-party dependency.

An allow configuration specifies exactly which elements and attributes are permitted and drops everything else. A remove configuration specifies what to strip and allows everything not explicitly listed. Allow configurations are generally safer because they default to blocking unknown or new elements rather than accidentally permitting them.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay