Living Standard — Last Updated 6 October 2025
TODO: introduction, what's all this?
partial interface Element {
WritableStream streamHTMLUnsafe(optional StreamHTMLUnsafeOptions options = {});
};
partial interface ShadowRoot {
WritableStream streamHTMLUnsafe(optional StreamHTMLUnsafeOptions options = {});
};
dictionary StreamHTMLUnsafeOptions {
boolean runScripts = false;
};
Element
's
streamHTMLUnsafe(
options
)
method
steps
are:
Let writable be a new WritableStream.
👋 Sketch of the streams setup:
Incoming chunks must all be of the same type, either strings or a trusted types wrapper. Check this on every chunk and treat mixing as an error.
If
the
first
chunk
is
not
a
trusted
types
wrapper
and
there
is
a
default
TT
policy,
create
a
transform
stream
using
createTransformStream
from
the
default
policy.
Then
pipe
chunks
through
that
transform
stream.
For trusted types handled "outside" (not by the internal transform stream) check that the chunks are in the same order and not duplicated/filtered/reordered.
👋 Sketch of the parser setup:
Let parser be a new fragment parser.
Add this to the stack of open elements .
If
options
["
runScripts
"],
don't
mark
scripts
as
already
executed.
Write chunks into the parser as they are written to writable .
Return writable .
Do a thing like this:
const policy = trustedTypes.createPolicy("my-policy", {
createTransformStream() {
return new TransformStream({
transform(chunk, controller) {
// TODO: some buffering
controller.enqueue(sanitize(chunk));
}
});
}
});
const response = await fetch('/fragments/something');
const transform = policy.createTransformStream();
const writable = element.streamHTMLUnsafe();
await
response.body.pipeThrough(transform).pipeTo(writable);
ShadowRoot
's
streamHTMLUnsafe(
options
)
method
steps
are: