Skip to content
Open
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 45 additions & 10 deletions dom.bs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ spec:html; type:element
<p>This specification depends on the Infra Standard. [[!INFRA]]

<p>Some of the terms used in this specification are defined in <cite>Encoding</cite>,
<cite>Selectors</cite>, <cite>Web IDL</cite>, <cite>XML</cite>, and <cite>Namespaces in XML</cite>.
<cite>Selectors</cite>, <cite>Trusted Types</cite>, <cite>Web IDL</cite>, <cite>XML</cite>, and
<cite>Namespaces in XML</cite>.
[[!ENCODING]]
[[!SELECTORS4]]
[[!TRUSTED-TYPES]]
[[!WEBIDL]]
[[!XML]]
[[!XML-NAMES]]
Expand Down Expand Up @@ -6520,8 +6522,8 @@ interface Element : Node {
sequence&lt;DOMString> getAttributeNames();
DOMString? getAttribute(DOMString qualifiedName);
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
[CEReactions] undefined setAttribute(DOMString qualifiedName, DOMString value);
[CEReactions] undefined setAttributeNS(DOMString? namespace, DOMString qualifiedName, DOMString value);
[CEReactions] undefined setAttribute(DOMString qualifiedName, (TrustedType or DOMString) value);
[CEReactions] undefined setAttributeNS(DOMString? namespace, DOMString qualifiedName, (TrustedType or DOMString) value);
[CEReactions] undefined removeAttribute(DOMString qualifiedName);
[CEReactions] undefined removeAttributeNS(DOMString? namespace, DOMString localName);
[CEReactions] boolean toggleAttribute(DOMString qualifiedName, optional boolean force);
Expand Down Expand Up @@ -6998,6 +7000,11 @@ string <var>namespace</var> (default null):</p>
<a for=/>attribute</a> <var>attr</var> and an <a for=/>element</a> <var>element</var>:

<ol>
<li><p>Let <var>verifiedValue</var> be the result of calling <a abstract-op>get
Trusted Types-compliant attribute value</a> with <var>attr</var>'s <a for=Attr>local name</a>,
<var>attr</var>'s <a for=Attr>namespace</a>, <var>element</var>, and <var>attr</var>'s
<a for=Attr>value</a>. [[!TRUSTED-TYPES]]

<li><p>If <var>attr</var>'s <a for=Attr>element</a> is neither null nor <var>element</var>,
<a>throw</a> an "{{InUseAttributeError!!exception}}" {{DOMException}}.

Expand All @@ -7013,6 +7020,8 @@ string <var>namespace</var> (default null):</p>

<li><p>Otherwise, <a lt="append an attribute">append</a> <var>attr</var> to <var>element</var>.

<li><p>Set <var>attr</var>'s <a for=Attr>value</a> to <var>verifiedValue</var>.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to check if this is in the right place in the algorithm.

cc @fred-wang

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(1) So in case oldAttr == attr, its value isn't updated.

(2) 'append an attribute' calls 'Handle attribute changes', and verifiedValue is set to attr after that. That doesn't seem right. Shouldn't value be set before?

Copy link
Member Author

@lukewarlow lukewarlow Jul 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. So in case oldAttr == attr, its value isn't updated.

Yes, I think that makes sense? If the attribute hasn't changed does it make sense to put it through Trusted Types default policy? I'll double check what browsers actually do in this case though.

  1. 'append an attribute' calls 'Handle attribute changes', and verifiedValue is set to attr after that. That doesn't seem right. Shouldn't value be set before?

Ah yeah, you're right, step 7 should be moved to step 5.

I've fixed 2 now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I double checked and for point 1 there's actually an interop bug here, WebKit (and Gecko) doesn't throw a TT error. Chromium currently does, so we can choose whichever behaviour we think is best here.

cc @annevk and @otherdaniel for your opinions

TLDR should doing

element.setAttributeNode(element.attributes[1]) - throw a TT error when TT is enforced (and where element.attributes[1] is something like an onclick attribute?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we either have to throw or do nothing at all, right? The latter is very weird as even no-op mutations result in a mutation record being queued. And queuing a mutation record for trusted type attributes without validation having occurred seems bad, so I think we have to throw.


<li><p>Return <var>oldAttr</var>.
</ol>
</div>
Expand Down Expand Up @@ -7291,17 +7300,21 @@ method steps are:
<a>HTML document</a>, then set <var>qualifiedName</var> to <var>qualifiedName</var> in
<a>ASCII lowercase</a>.

<li><p>Let <var>verifiedValue</var> be the result of calling <a abstract-op>get
Trusted Types-compliant attribute value</a> with <var>qualifiedName</var>, null, <a>this</a>, and
<var>value</var>. [[!TRUSTED-TYPES]]

<li><p>Let <var>attribute</var> be the first <a>attribute</a> in <a>this</a>'s
<a for=Element>attribute list</a> whose <a for=Attr>qualified name</a> is <var>qualifiedName</var>,
and null otherwise.
<!-- This is step 2 of "get an attribute by name", modified as appropriate -->

<li><p>If <var>attribute</var> is null, create an <a>attribute</a> whose
<a for=Attr>local name</a> is <var>qualifiedName</var>, <a for=Attr>value</a> is
<var>value</var>, and <a for=Node>node document</a> is <a>this</a>'s <a for=Node>node document</a>,
then <a lt="append an attribute">append</a> this <a>attribute</a> to <a>this</a>, and then return.
<var>verifiedValue</var>, and <a for=Node>node document</a> is <a>this</a>'s
<a for=Node>node document</a>, then <a lt="append an attribute">append</a> this <a>attribute</a>
to <a>this</a>, and then return.

<li><p><a lt="change an attribute">Change</a> <var>attribute</var> to <var>value</var>.
<li><p><a lt="change an attribute">Change</a> <var>attribute</var> to <var>verifiedValue</var>.
</ol>

<p>The
Expand All @@ -7312,8 +7325,12 @@ method steps are:
<li><p>Let <var>namespace</var>, <var>prefix</var>, and <var>localName</var> be the result of
passing <var>namespace</var> and <var>qualifiedName</var> to <a>validate and extract</a>.

<li><p><a>Set an attribute value</a> for <a>this</a> using <var>localName</var>, <var>value</var>,
and also <var>prefix</var> and <var>namespace</var>.
<li><p>Let <var>verifiedValue</var> be the result of calling <a abstract-op>get
Trusted Types-compliant attribute value</a> with <var>localName</var>, <var>namespace</var>,
<var>element</var>, and <var>value</var>. [[!TRUSTED-TYPES]]

<li><p><a>Set an attribute value</a> for <a>this</a> using <var>localName</var>,
<var>verifiedValue</var>, and also <var>prefix</var> and <var>namespace</var>.
</ol>

<p>The
Expand Down Expand Up @@ -7891,7 +7908,25 @@ string <var>value</var>, run these steps:
<li><p>If <var>attribute</var>'s <a for=Attr>element</a> is null, then set <var>attribute</var>'s
<a for=Attr>value</a> to <var>value</var>.

<li><p>Otherwise, <a lt="change an attribute">change</a> <var>attribute</var> to <var>value</var>.
<li>
<p>Otherwise:

<ol>
<li><p>Let <var>originalElement</var> be <var>attribute</var>'s <a for=Attr>element</a>.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<li><p>Let <var>originalElement</var> be <var>attribute</var>'s <a for=Attr>element</a>.
<li><p>Let <var>element</var> be <var>attribute</var>'s <a for=Attr>element</a>.


<li><p>Let <var>verifiedValue</var> be the result of calling <a abstract-op>get
Trusted Types-compliant attribute value</a> with <var>attribute</var>'s
<a for=Attr>local name</a>, <var>attribute</var>'s <a for=Attr>namespace</a>, <a>this</a>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no this here.

and <var>value</var>. [[!TRUSTED-TYPES]]

<li><p>If <var>attribute</var>'s <a for=Attr>element</a> is null, then set <var>attribute</var>'s
<a for=Attr>value</a> to <var>verifiedValue</var>, and return.

<li><p>If <var>attribute</var>'s <a for=Attr>element</a> is not <var>originalElement</var>, then
return.
Comment on lines +7922 to +7926
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be nicer if we throw for both of these cases as they result from the policy changing aspects of the attribute that it probably shouldn't? But maybe that's not compatible with what Chromium does.

Also, the other changes are made directly in setAttribute and setAttributeNS. Do we end up invoking the policy early enough here for the various call sites? It seems like there would be a difference in exception order.


<li><p><a lt="change an attribute">Change</a> <var>attribute</var> to <var>verifiedValue</var>.
</ol>
</ol>

<p>The {{Attr/value}} setter steps are to <a>set an existing attribute value</a> with <a>this</a>
Expand Down