Living Standard — Last Updated 2 October 2025
TODO: introduction, what's all this?
partial interface Element {
WritableStream patchUnsafe(optional PatchUnsafeOptions options = {});
};
partial interface ShadowRoot {
WritableStream patchUnsafe(optional PatchUnsafeOptions options = {});
};
dictionary PatchUnsafeOptions {
boolean runScripts = false;
};
Element
's
patchUnsafe(
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, bytes, or a trusted types wrapper.
Some decisions are made based on the first chunk:
If
it's
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.
If it's bytes, create an UTF-8 TextDecoderStream and pipe chunks through that.
TODO: which should happen first? should we allow the TT transform stream to take bytes as input, or guarantee that it's strings by then?
As chunks are coming through, before handing them to the parser, check that they're all of the same type. For trusted types, also 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 .
When
a
template
element
with
a
patchfor
attribute
comes
out
of
the
parser,
find
the
target
node
by
ID
and
set
that
as
the
parser's
insertion
point.
The first time an element is patched, replace all children. Subsequent patches to the same target append children.
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.patchUnsafe();
await
response.body.pipeThrough(transform).pipeTo(writable);
ShadowRoot
's
patchUnsafe(
options
)
method
steps
are: