-
Notifications
You must be signed in to change notification settings - Fork 22.8k
Element.innerHTML - add info trusted types #40423
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@@ -79,15 +153,6 @@ document.documentElement.innerHTML = `<pre>${document.documentElement.innerHTML. | |||
)}</pre>`; | |||
``` | |||
|
|||
#### Operational details |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting I guess. But it doesn't actually matter. If it did/does it should be in the description part.
Preview URLs External URLs (3)URL:
URL:
(comment last updated: 2025-07-21 07:07:10) |
24677d9
to
cfaddcf
Compare
FYI @lukewarlow @wbamberg - this is the trusted types update for All the examples use trustedHTML. This also shows the first live example use of the tinyfill in the docs. This is duplication with the main docs, but it feels very practical to me given the current state of trustedtypes. |
@@ -105,15 +119,35 @@ code { | |||
|
|||
#### JavaScript | |||
|
|||
```js hidden |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decided to hide the tinyfill in this case. Do you think it should be here. Or perhaps a note "if trusted types not supported you should add a tinyfill".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just comments on innerHTML
for now.
Getting the property returns a string containing the HTML serialization of the element's descendants. | ||
|
||
Setting the value of `innerHTML` removes all of the element's descendants and replaces them with nodes constructed by parsing the HTML given in the assigned {{domxref("TrustedHTML")}} or string. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might help some of the other discussion to be clearer about the types that this property can accept. As it stands, especially the "Setting the value" para starts with what it does, not what types it accepts, which turns out to be important of course for when we want to talk about trusted types.
Maybe something like:
Getting the property returns a string containing the HTML serialization of the element's descendants. | |
Setting the value of `innerHTML` removes all of the element's descendants and replaces them with nodes constructed by parsing the HTML given in the assigned {{domxref("TrustedHTML")}} or string. | |
Getting the property returns a string containing the HTML serialization of the element's descendants. | |
Setting the property accepts either a {{domxref("TrustedHTML")}} object or a string. It parses this value as HTML and replaces all the element's descendants with the result. |
When set to the `null` value, that `null` value is converted to the empty string (`""`), so `elt.innerHTML = null` is equivalent to `elt.innerHTML = ""`. | ||
Note that {{htmlelement("script")}} elements in the assigned value are injected but not executed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe better in the security section, where it is mentioned? Anyway, seems a poor fit for "Value".
|
||
Shadow roots are dropped from the serialized and injected HTML. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also doesn't seem a good fit for "Value", and is already covered in "Description".
The serialization of the DOM tree read from the property does not include {{glossary("shadow tree", "shadow roots")}} — if you want to get a HTML string that includes shadow roots, you must instead use the {{domxref("Element.getHTML()")}} or {{domxref("ShadowRoot.getHTML()")}} methods. | ||
|
||
Similarly, when setting element content using `innerHTML`, the HTML string is parsed into DOM elements that do not contain shadow roots. | ||
So for example [`<template>`](/en-US/docs/Web/HTML/Reference/Elements/template) is parsed into as {{domxref("HTMLTemplateElement")}}, whether or not the [`shadowrootmode`](/en-US/docs/Web/HTML/Reference/Elements/template#shadowrootmode) attribute is specified. | ||
In order to set an element's contents from an HTML string that includes declarative shadow roots, you must instead use {{domxref("Element.setHTMLUnsafe()")}} or {{domxref("ShadowRoot.setHTMLUnsafe()")}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this is about a very distinct aspect of innerHTML, I would have these two paragraphs under an H3 like "Shadow DOM considerations" or something, and move it after the para about "Note that some browsers...".
You might also consider moving "Note that some browsers..." into "Security considerations", maybe.
|
||
You can mitigate these issues by always assigning {{domxref("TrustedHTML")}} objects instead of strings, and [enforcing trusted type](/en-US/docs/Web/API/Trusted_Types_API#using_a_csp_to_enforce_trusted_types) using the [`require-trusted-types-for`](/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for) CSP directive. | ||
This ensures that the input is passed through a transformation function, which has the chance to [sanitize](/en-US/docs/Web/Security/Attacks/XSS#sanitization) the input to remove potentially dangerous markup before it is injected. | ||
This is demonstrated in the following sections. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unclear. Which of the following sections demonstrate this? As a reader I want a direct link to a concrete example of this.
This is then wrapped in a {{HTMLElement("pre")}} element. | ||
Then the value of `innerHTML` is changed to this new string. | ||
As a result, the document contents are replaced with a display of the page's entire source code. | ||
Next create a {{domxref("TrustedTypePolicy")}} that defines a {{domxref("TrustedTypePolicy/createHTML", "createHTML()")}} for transforming an input string into {{domxref("TrustedHTML")}} instances. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Next create a {{domxref("TrustedTypePolicy")}} that defines a {{domxref("TrustedTypePolicy/createHTML", "createHTML()")}} for transforming an input string into {{domxref("TrustedHTML")}} instances. | |
Next we create a {{domxref("TrustedTypePolicy")}} that defines a {{domxref("TrustedTypePolicy/createHTML", "createHTML()")}} for transforming an input string into {{domxref("TrustedHTML")}} instances. |
Very pedantic, but this started "first we" so perhaps "next we" afterwards? Just "next" implicitly changes it from first-person to second.
``` | ||
|
||
#### Operational details | ||
Then use this `policy` object to create a `TrustedHTML` object from the potentially unsafe input string, and assign the result to the element: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then use this `policy` object to create a `TrustedHTML` object from the potentially unsafe input string, and assign the result to the element: | |
Then we use this `policy` object to create a `TrustedHTML` object from the potentially unsafe input string, and assign the result to the element: |
</ul> | ||
```js | ||
// Create a TrustedHTML instance using the policy | ||
document.body.textContent = policy.createHTML(policy.createHTML("")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this supposed to be assigning to textContent?
``` | ||
|
||
#### JavaScript | ||
Note that in this case we're setting the element to an empty string, which we know is safe. | ||
If we weren't [enforcing trusted types](/en-US/docs/Web/API/Trusted_Types_API#using_a_csp_to_enforce_trusted_types) we could instead directly assign the empty string: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we should encourage this. AIUI, if we don't enforce the use of trusted types, we lose a lot of the protection they offer (because you don't know any more whether somewhere in your codebase you might be unsafe).
So I would omit this.
``` | ||
|
||
Please note that using `innerHTML` to append HTML elements (e.g., `el.innerHTML += "<a href='…'>link</a>"`) will result in the removal of any previously set event listeners. | ||
That is, after you append any HTML element that way you won't be able to listen to the previously set event listeners. | ||
### Logging messages using innerHTML |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this example worth keeping? Is this a pattern we want to encourage, versus explicitly creating the DOM elements to put in the log?
and I also wonder, is it a good idea to recommend people to define a no-op TT policy? To what extent does that open up a hole in the whole thing?
This updates the following properties to explain how they are used with TrustedTypes:
Element.innerHTML
Element.insertAdjacentHTML()
This is in progress:
This does not mention the sanitizer methods as alternatives since the
setHTML()
is not implemented anywhere, and the sanitizer insetHTMLUnsafe()
is not yet implemented. We're in separate discussion on those and when they are in a release we can revisit.Part of #37518 (tracking issue)