JavaScript Element setHTMLUnsafe() Method

Beginner
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Baseline 2025
Instance method

What You’ll Learn

Element.setHTMLUnsafe() is an instance method that parses HTML into a DocumentFragment and replaces the element’s subtree. Unlike innerHTML, it parses declarative shadow roots. Learn MDN’s injection-sink warnings, TrustedHTML + Trusted Types, optional Sanitizer configs, when to prefer setHTML(), and five try-it labs aligned with MDN.

01

Kind

Instance method

02

Returns

undefined

03

Args

input, options

04

Default

No sanitizer

05

Shadow DOM

Declarative roots

06

Status

Baseline 2025

Introduction

Sometimes you need to inject HTML from a string — CMS output, server-rendered fragments, or components with declarative shadow DOM. The familiar element.innerHTML = html approach does not parse declarative shadow roots and offers no built-in sanitization.

element.setHTMLUnsafe(input, options) parses the string into a DocumentFragment, optionally filters it with a Sanitizer, and replaces the element’s subtree (MDN). Declarative shadow roots in the input are parsed into real ShadowRoot nodes — something innerHTML cannot do.

⚠️
Injection sink (MDN)

The “Unsafe” suffix means no XSS filtering by default. Without a sanitizer, all HTML entities are injected — potentially less safe than innerHTML for script execution. MDN: almost always prefer setHTML() for user content.

This page is part of JavaScript Element. Pair with setHTML() (XSS-safe alternative), getHTML() (serialize out), and shadowRoot (imperative shadow DOM).

Understanding the setHTMLUnsafe() Method

Calling el.setHTMLUnsafe(input, options) parses input and replaces the element’s contents with the resulting subtree (MDN).

  • It is an instance method on Element.
  • inputTrustedHTML instance or HTML string (MDN).
  • options.sanitizer — optional Sanitizer, SanitizerConfig, or "default" (XSS-safe default config). If omitted, no sanitizer runs (MDN).
  • Returns undefined.
  • Parses declarative shadow roots; only the first per host is created (MDN).
  • Drops elements invalid in the current element’s context (e.g. tr outside table) (MDN).
  • Throws TypeError for invalid sanitizer config (MDN).
  • Safe alternative for user HTML: setHTML() (MDN).

📝 Syntax

General form of Element.setHTMLUnsafe (MDN):

JavaScript
setHTMLUnsafe(input)
setHTMLUnsafe(input, options)

Parameters

  • inputTrustedHTML or HTML string to parse and inject (MDN).
  • options.sanitizer (optional) — Sanitizer, SanitizerConfig, or "default". If omitted, no sanitizer is used (MDN).

Return value

undefined (MDN).

Exceptions

  • TypeError — invalid SanitizerConfig, invalid string for sanitizer, or non-Sanitizer value (MDN).

Common patterns

JavaScript
const target = document.getElementById("target");
const html = '<p>Hello</p><script>alert(1)</script>';

// No sanitizer — all entities injected (MDN: injection sink!)
target.setHTMLUnsafe(html);

// Default XSS-safe sanitizer config (MDN)
target.setHTMLUnsafe(html, { sanitizer: "default" });

// TrustedHTML — no sanitizer needed when policy already sanitized
const trusted = policy.createHTML(html);
target.setHTMLUnsafe(trusted);

// Custom sanitizer — can allow script unlike setHTML() (MDN)
const sanitizer = new Sanitizer({ elements: ["div", "p", "script"] });
target.setHTMLUnsafe(html, { sanitizer });

⚡ Quick Reference

GoalCode
Inject trusted HTMLel.setHTMLUnsafe(trustedHtml)
XSS-safe filteringel.setHTMLUnsafe(html, { sanitizer: "default" })
Custom sanitizerel.setHTMLUnsafe(html, { sanitizer })
Declarative shadow DOMel.setHTMLUnsafe(htmlWithShadowTemplate)
Feature detecttypeof el.setHTMLUnsafe === "function"
User content (MDN)Prefer setHTML()

🔍 At a Glance

Four facts to remember about Element.setHTMLUnsafe().

Returns
undefined

No value

Default
no filter

Injection sink

Shadow DOM
parsed

vs innerHTML

Status
baseline

Sep 2025

📋 setHTMLUnsafe() vs other HTML APIs

setHTMLUnsafe()setHTML()innerHTML
Default sanitizesNoYes (always)No
User input (MDN)AvoidRecommendedDangerous
Declarative shadow rootsYes (MDN)YesNo
Can allow scriptWith custom sanitizerNever (MDN)Yes
ReturnsundefinedundefinedAssignment result
Best forTrusted HTML, shadow DOM, edge casesUntrusted HTML stringsSimple trusted markup

Examples Gallery

Examples follow MDN Element.setHTMLUnsafe() patterns. Use View Output or Try It Yourself for each case. Feature-detect setHTMLUnsafe and Sanitizer in supporting browsers.

📚 Getting Started

MDN’s injection sink demo—no sanitizer injects all HTML entities.

Example 1 — No sanitizer (MDN)

Parse and inject HTML without filtering. Use only with fully trusted strings.

JavaScript
const html = '<p>Hello</p><strong>Trusted markup</strong>';
const target = document.getElementById("target");

// No sanitizer — everything in the string is injected (MDN)
target.setHTMLUnsafe(html);

console.log(target.innerHTML);
Try It Yourself

How It Works

MDN: when no sanitizer is passed, all HTML entities in the input are injected. This is an injection sink—never pass user-controlled strings here.

Example 2 — TrustedHTML + Trusted Types (MDN)

Pass a TrustedHTML object so input is sanitized before injection.

JavaScript
// Tinyfill when trustedTypes is missing (MDN pattern)
if (typeof trustedTypes === "undefined") {
  trustedTypes = { createPolicy: (n, rules) => rules };
}

const policy = trustedTypes.createPolicy("my-policy", {
  createHTML: (input) => DOMPurify.sanitize(input)
});

const untrusted = 'abc <script>alert(1)</script> def';
const trustedHTML = policy.createHTML(untrusted);
const target = document.getElementById("target");

// TrustedHTML already sanitized — no sanitizer param (MDN)
target.setHTMLUnsafe(trustedHTML);

console.log(target.innerHTML);
Try It Yourself

How It Works

MDN recommends TrustedHTML with a TrustedTypePolicy so sanitization is centralized. Enforce with the require-trusted-types-for CSP directive in production.

📈 Sanitizer Patterns

Default and custom Sanitizer configs with setHTMLUnsafe().

Example 3 — Default sanitizer "default" (MDN)

Apply the XSS-safe default sanitizer configuration when you cannot use setHTML().

JavaScript
const untrusted = 'abc <script>alert(1)</script> def';
const target = document.getElementById("target");

target.setHTMLUnsafe(untrusted, { sanitizer: "default" });

console.log(target.innerHTML); // script removed
Try It Yourself

How It Works

MDN: if you cannot use TrustedHTML or setHTML(), the next safest option is setHTMLUnsafe() with the default sanitizer configuration.

Example 4 — Custom Sanitizer allows script (MDN)

Unlike setHTML(), a custom sanitizer can allow script elements.

JavaScript
const html = '<div><p>Hi</p><script>console.log("injected")</script></div>';
const target = document.getElementById("target");

const sanitizer = new Sanitizer({
  elements: ["div", "p", "script"] // script allowed with setHTMLUnsafe (MDN)
});

target.setHTMLUnsafe(html, { sanitizer });

console.log(target.innerHTML);
Try It Yourself

How It Works

MDN: setHTMLUnsafe() does not force removal of XSS-unsafe entities. A custom sanitizer can allow script — something setHTML() never permits.

Example 5 — onclick handlers: three APIs compared (MDN)

See how setHTML(), setHTMLUnsafe(), and innerHTML treat event handlers.

JavaScript
const input = '<img src=x onclick=alert(1) onerror=alert(2)>';
const target = document.querySelector("#target");

// Safe — strips onclick/onerror (MDN)
target.setHTML(input);
console.log("setHTML:", target.innerHTML);

// Unsafe — keeps event handler attributes (MDN)
target.setHTMLUnsafe(input);
console.log("setHTMLUnsafe:", target.innerHTML);

// Same as setHTMLUnsafe for handlers (MDN)
// target.innerHTML = input;
Try It Yourself

How It Works

MDN’s comparison: setHTML() removes all XSS-unsafe entities. setHTMLUnsafe() without a sanitizer keeps handlers like onclick. Use a sanitizer with allowAttribute("onclick") only when you have a controlled edge case.

🚀 Common Use Cases

  • Injecting HTML that contains declarative shadow roots (MDN).
  • Trusted server-rendered fragments where sanitization happened upstream.
  • Using TrustedHTML + Trusted Types at injection sinks (MDN).
  • Applying sanitizer: "default" when setHTML() is unavailable.
  • Edge cases requiring specific unsafe elements via a controlled Sanitizer.
  • Pairing with setHTML() for user-facing content.

🧠 How setHTMLUnsafe() Parses and Injects

1

Receive input

el.setHTMLUnsafe(input) accepts a string or TrustedHTML (MDN).

Input
2

Optional sanitization

Apply Sanitizer, config, or "default" — or skip if omitted (MDN).

Sanitize?
3

Parse to DocumentFragment

Declarative shadow roots become real ShadowRoot nodes; invalid-in-context tags dropped (MDN).

Parse
4

Replace subtree

DOM updated; return value is undefined. Inspect with innerHTML or DevTools.

📝 Notes

  • Baseline 2025 on MDN — newly available since September 2025. Feature-detect on older browsers.
  • Not Deprecated, Experimental, or Non-standard — defined in the HTML specification.
  • Injection sink: no sanitizer by default; potentially less safe than innerHTML for scripts (MDN).
  • MDN: almost always prefer setHTML() when available for user-provided HTML.
  • Use TrustedHTML + Trusted Types CSP to audit sanitization at few central points (MDN).
  • Related: setHTML(), getHTML(), innerHTML, shadowRoot, JavaScript hub.

Browser Support

Element.setHTMLUnsafe() is Baseline Newly available (MDN: across latest browsers since September 2025). Feature-detect on older engines. Logos use the shared browser-image-sprite.png sprite from this project.

Baseline 2025

Element.setHTMLUnsafe()

Parse HTML with optional sanitization — supports declarative shadow roots.

Baseline Newly available 2025
Google Chrome Supported in current releases — feature-detect older
Yes
Microsoft Edge Supported in current releases — feature-detect older
Yes
Mozilla Firefox Supported in current releases — feature-detect older
Yes
Apple Safari Supported in current releases — feature-detect older
Yes
Opera Follow Chromium support
Yes
Internet Explorer Not supported — use innerHTML or server sanitization
No
setHTMLUnsafe() Baseline

Bottom line: Detect typeof el.setHTMLUnsafe === "function". Prefer setHTML() for user content. Use TrustedHTML or sanitizer: "default" when you must call this API.

Conclusion

Element.setHTMLUnsafe() parses HTML into the DOM with optional sanitization. MDN recommends setHTML() for almost all user content. Use setHTMLUnsafe() for declarative shadow DOM, TrustedHTML workflows, or controlled edge cases with a custom Sanitizer.

Continue with setHTML(), shadowRoot, getHTML(), or the JavaScript hub.

💡 Best Practices

✅ Do

  • Prefer setHTML() for user-provided HTML (MDN)
  • Use TrustedHTML + Trusted Types at injection sinks
  • Pass sanitizer: "default" when you cannot use setHTML()
  • Feature-detect: typeof el.setHTMLUnsafe === "function"
  • Use for declarative shadow root markup (MDN)

❌ Don’t

  • Pass raw user strings without sanitization
  • Assume the “Unsafe” name means safe by default
  • Choose this over setHTML() without a clear reason
  • Allow script unless you fully control the source
  • Skip Trusted Types in production injection sinks

Key Takeaways

Knowledge Unlocked

Five things to remember about Element.setHTMLUnsafe()

Parse HTML with optional filtering — use with care at injection sinks.

5
Core concepts
⚠️ 02

Default

no sanitizer

Sink
🌀 03

Shadow DOM

declarative

Parse
🛡️ 04

TrustedHTML

preferred

Security
🌐 05

Support

Baseline 2025

Sep 2025

❓ Frequently Asked Questions

It parses HTML input into a DocumentFragment, optionally sanitizes it, and replaces the element's subtree in the DOM (MDN). Unlike innerHTML, declarative shadow roots in the input are parsed.
No. MDN marks Element.setHTMLUnsafe() as Baseline 2025 (newly available since September 2025). It is not Deprecated, Experimental, or Non-standard.
undefined. There is no return value (MDN).
MDN: almost always. setHTML() always removes XSS-unsafe entities. Use setHTMLUnsafe() only for edge cases like declarative shadow roots or when you must allow specific unsafe HTML with a controlled sanitizer.
No by default. MDN warns it is an injection sink and potentially less safe than innerHTML when no sanitizer is used. Prefer TrustedHTML with Trusted Types, or setHTML() for user content.
Optional Sanitizer, SanitizerConfig, or "default" (XSS-safe default config). If omitted, no sanitizer runs and all HTML entities are injected (MDN).
Did you know?

MDN notes that setHTMLUnsafe() parses declarative shadow roots into real ShadowRoot nodes, while innerHTML does not. If your markup includes <template shadowrootmode="open">, this API is the right tool — but still sanitize untrusted input first.

Next: shadowRoot

Continue the Element series with the shadow DOM property.

shadowRoot →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful