Browser Support Note:
- setHTMLUnsafe is supported across all browsers.
- setHTML is in the process of being standardized and is currently available only in Firefox behind a flag.
- getHTML has been supported in Chrome and Edge since version 125.
Introduction to setHTMLUnsafe
Recently, browsers have introduced a new method called setHTMLUnsafe
. The term “unsafe” in this context means that, similar to innerHTML
, it does not sanitize the input. This naming is somewhat inconsistent with previous APIs such as innerHTML
and eval()
, which do not have the “Unsafe” suffix despite similar risks. The key difference now is that we have both a safe version (setHTML
) and an unsafe version (setHTMLUnsafe
).
According to the Sanitizer API spec:
The “safe” methods will not generate any markup that executes scripts, making them safe from XSS (Cross-Site Scripting) attacks.
Consider this example:
form.addEventListener('submit', function(event) {
event.preventDefault();
const markup = `<h2>${input.value}</h2>`;
div.innerHTML = markup;
});
If a user inputs <img src=doesnotexist onerror="alert('Potential XSS Attack')">
, the JavaScript code will execute in the browser. This risk persists with setHTMLUnsafe
.
However, using setHTML
, only the image tag <img src="doesnotexist">
is inserted, stripping out any JavaScript. This enhances security by preventing the execution of potentially malicious scripts.
The Role of setHTMLUnsafe
With the advent of setHTML
, one might wonder why we need setHTMLUnsafe
. The answer lies in the implementation of declarative shadow DOM.
The <template>
element in HTML serves two purposes:
- Holding a fragment of HTML that can be used later via JavaScript.
- Creating a shadow DOM instantly when the
shadowrootmode
attribute is present.
While innerHTML
works well for the first use case, it fails to handle the second. For example:
const main = document.querySelector('main');
main.innerHTML = `
<h2>I am in the Light DOM</h2>
<div>
<template shadowrootmode="open">
<style>
h2 { color: blue; }
</style>
<h2>Shadow DOM</h2>
</template>
</div>`;
In this case, innerHTML
injects the <template>
element but does not render its contents as shadow DOM, regardless of the shadowrootmode
attribute.
Conversely, using setHTML
:
const main = document.querySelector('main');
main.setHTML(`
<h2>I am in the Light DOM</h2>
<div>
<template shadowrootmode="open">
<style>
h2 { color: blue; }
</style>
<h2>Shadow DOM</h2>
</template>
</div>`);
Here, the <template>
and its contents are removed, treating it as an “unsafe node.” To dynamically add declarative shadow DOM, browsers introduced setHTMLUnsafe
:
const main = document.querySelector('main');
main.setHTMLUnsafe(`
<h2>I am in the Light DOM</h2>
<div>
<template shadowrootmode="open">
<style>
h2 { color: blue; }
</style>
<h2>Shadow DOM</h2>
</template>
</div>`);
Using setHTMLUnsafe
, the contents of the <template>
are rendered inside the shadow DOM.
Read more @mozilla.org
Read also: 20 Must Know Laptop Shortcuts For Developers And Everyone
Introducing getHTML
setHTML
and setHTMLUnsafe
do not fully replace innerHTML
, which can both set and get HTML. The complementary function for getting HTML content is getHTML
.
const main = document.querySelector('main');
const html = main.getHTML();
By default, getHTML
does not return any markup from within a shadow DOM, but it can be configured to do so:
const main = document.querySelector('main');
const html = main.getHTML({ serializableShadowRoots: true });
Setting serializableShadowRoots
to true will serialize all shadow DOM trees that have opted in for serialization. A template element can opt-in using the shadowrootserializable
attribute:
<template shadowrootmode="open" shadowrootserializable></template>
Similarly, in JavaScript, the attachShadow
method has a boolean serializable
option:
this.attachShadow({ mode: "open", serializable: true });
It is also possible to serialize only specific shadow DOM trees by passing an array of shadow roots:
const markup = main.getHTML({
shadowRoots: [document.querySelector('.example').shadowRoot]
});
All shadow roots in the array will be serialized, even if they are not marked as serializable.
Read more @mozilla.org
These new methods—setHTMLUnsafe
, setHTML
, and getHTML
—offer more control and flexibility for developers working with dynamic content and shadow DOMs in modern web development.
Conclusion
Understanding and leveraging these new methods can significantly enhance how you manage dynamic content on your web pages. Whether you need the safety of setHTML
or the flexibility of setHTMLUnsafe
for advanced use cases, these tools provide robust solutions for modern web development.
Source: BlogTech