这是indexloc提供的服务,不要输入任何密码
Skip to content

Introduce attribute reflection extended attributes #11450

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

lukewarlow
Copy link
Member

@lukewarlow lukewarlow commented Jul 14, 2025

A number of extended attributes are added which trigger IDL attribute reflection:

  • [Reflect] and [Reflect=string] cover basic content attribute reflection cases.

  • [ReflectSetter] and [ReflectSetter=string] covers content attribute reflection only for setters.

  • [ReflectURL] and [ReflectURL=string] covers reflection of USV attributes, which represent URLs.

  • [ReflectNonNegative] and [ReflectNonNegative=string] covers reflection of long attributes that should be limited to only non-negative numbers.

  • [ReflectPositive] and [ReflectPositive=string] covers reflection of double and unsigned long attributes which should be limited to positive numbers.

  • [ReflectPositiveWithFallback] and [ReflectPositiveWithFallback=string] covers reflection of double and unsigned long attributes which should be limited to positive numbers with fallback.

Additionally:

  • [ReflectRange=(integer, integer)] can be used alongside others on unsigned long attributes that should be clamped to a range.

  • [ReflectDefault=number] can be used alongside others on double, long and unsigned long attributes that should be reflected with a default value.

Depends on: whatwg/webidl#1503

  • At least two implementers are interested (and none opposed):
  • Tests are written and can be reviewed and commented upon at:
  • Implementation bugs are filed:
    • Chromium: …
    • Gecko: …
    • WebKit: …
    • Deno (only for timers, structured clone, base64 utils, channel messaging, module resolution, web workers, and web storage): …
    • Node.js (only for timers, structured clone, base64 utils, channel messaging, and module resolution): …
  • Corresponding HTML AAM & ARIA in HTML issues & PRs:
  • MDN issue is filed: …
  • The top of this comment includes a clear commit message to use.

See #3238

(See WHATWG Working Mode: Changes for more details.)


/common-dom-interfaces.html ( diff )
/dom.html ( diff )
/edits.html ( diff )
/embedded-content-other.html ( diff )
/embedded-content.html ( diff )
/form-control-infrastructure.html ( diff )
/form-elements.html ( diff )
/forms.html ( diff )
/grouping-content.html ( diff )
/iframe-embed-object.html ( diff )
/image-maps.html ( diff )
/index.html ( diff )
/input.html ( diff )
/interaction.html ( diff )
/interactive-elements.html ( diff )
/media.html ( diff )
/obsolete.html ( diff )
/popover.html ( diff )
/scripting.html ( diff )
/semantics.html ( diff )
/tables.html ( diff )
/text-level-semantics.html ( diff )

A number of extended attributes are added which trigger IDL attribute reflection:

- [Reflect] and [Reflect=string] cover basic content attribute reflection cases.
- [ReflectURL] and [ReflectURL=string] covers reflection of USV attributes, which represent URLs.

- [ReflectNonNegative] and [ReflectNonNegative=string] covers reflection of long attributes that should be limited to only non-negative numbers.

- [ReflectPositive] and [ReflectPositive=string] covers reflection of double and unsigned long attributes which should be limited to positive numbers.

- [ReflectPositiveWithFallback] and [ReflectPositiveWithFallback=string] covers reflection of double and unsigned long attributes which should be limited to positive numbers with fallback.

Additionally:
- [ReflectRange=(integer, integer)] can be used alongside others on unsigned long attributes that should be clamped to a range.

- [ReflectDefault=number] can be used alongside others on double, long and unsigned long attributes that should be reflected with a default value.
@domenic
Copy link
Member

domenic commented Jul 15, 2025

I'm having a hard time reviewing this because, despite the bold text in the beginning, it seems to mix up the enumerated attribute handling into the same PR as the non-enumerated attribute work.

@lukewarlow
Copy link
Member Author

Apologies I think it got changed by a build task after I updated it. If you look purely at the first commit it should be easy enough to review. I think I'll revert the enumerated stuff and move it to a separate tag on PR.

@lukewarlow
Copy link
Member Author

I've dropped the second commit from this PR so it should be reviewable now.

Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

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

Would it be possible to start with [ReflectURL] and take them in turns? I don't really know what @domenic would prefer so wait for him to say something, but I would find it easier if we did them incrementally.

@lukewarlow
Copy link
Member Author

Would it be possible to start with [ReflectURL] and take them in turns? I don't really know what @domenic would prefer so wait for him to say something, but I would find it easier if we did them incrementally.

To clarify you mean add a PR that does just [ReflectURL] and then a follow up that does just [Reflect]?

I'm happy to split this however reviewers think is best.

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

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

Overall this is quite impressive. The comprehensive updates to the prose and IDL are wonderful. I especially like the touch of adding the data-xs to the string arguments so you link to the content attribute definitions.

In terms of splitting the PR, I think it would be reasonable to either do just [Reflect], or do [Reflect] and [ReflectURL], or do all of these at once. I don't think it will change the complexity of the review too much, and I don't feel strongly which path we take.

This specification text direction, which builds on top of and preserves the existing prose-based infrastructure, is different than what I was expecting. I was picturing that we would rebuild the specification to be centered around the extended attributes, getting rid of concepts like "reflected target", "reflected IDL attribute", "reflected content attribute", "treated as a URL", "limited to only positive numbers", etc. Instead we would do something like:

IDL attributes annotated with the [Reflect] content attribute have the following getter steps: [...] and the following setter steps: [...]

and then everything there would be phrased in terms of the IDL concepts, like the extended attribute arguments, the IDL attribute type, <span>this</span>, or the presence of other auxiliary extended attributes.

I think my vision is cleaner, as it has fewer layers of abstraction. It also prevents people from attempting to do reflection in prose, which seems like a good idea. And it's closer to how one might implement these. However, it's certainly less incremental. What do you think?

@lukewarlow
Copy link
Member Author

lukewarlow commented Jul 16, 2025

This specification text direction, which builds on top of and preserves the existing prose-based infrastructure, is different than what I was expecting. I was picturing that we would rebuild the specification to be centered around the extended attributes, getting rid of concepts like "reflected target", "reflected IDL attribute", "reflected content attribute", "treated as a URL", "limited to only positive numbers", etc. Instead we would do something like:

IDL attributes annotated with the [Reflect] content attribute have the following getter steps: [...] and the following setter steps: [...]

and then everything there would be phrased in terms of the IDL concepts, like the extended attribute arguments, the IDL attribute type, this, or the presence of other auxiliary extended attributes.

I think my vision is cleaner, as it has fewer layers of abstraction. It also prevents people from attempting to do reflection in prose, which seems like a good idea. And it's closer to how one might implement these. However, it's certainly less incremental. What do you think?

So my thought process was to build this in a way that was as incremental as possible. Which is why it's currently in the form I've used.

I don't know that we'll ever be able to fully get rid of spec prose for reflection, but it might be that the end situation has few enough special cases that their prose should just be rewritten to not mention reflection and then we could drop many of these existing concepts.

My other hesitation along the same lines is I don't know what other specs use these algorithms. I didn't want to accidentally break URL reflection from another spec by removing the prose concept (though I'll admit it's rather vague at the moment so it's ideal anyway).

I think my preference would be to write them in terms of the existing prose initially and then once we've moved everything across (including looking at other specs). We can possibly rewrite how they're defined to drop the old approach. It would be purely editorial (I guess normative because we're removing existing algorithms?).

That way we don't break existing stuff and avoid duplication at the same time?

One other question is are we aiming to go for 100% coverage in IDL. Or is it okay if we end up with some still defined manually.

There's a number of odd cases that aren't currently possible to do in the IDL proposal.

  • Document.dir reflects the content attribute of the html element

  • form.action and form.formAction's missing and empty value default is to return the document's URL instead (Uses ReflectSetter to handle the simple setter case)

  • .autocomplete returns IDL-exposed autofill value internal state (Uses ReflectSetter to handle the simple setter case)

  • canvas.width and canvas.height are limited to non-negative integers per attribute parsing but the current spec prose and a quick test in chrome shows that setter steps are not equivalent to [ReflectNonNegative,ReflectDefault=X]. (it doesn't throw when you set an invalid value, unlike the existing reflection)

  • .tabIndex tabIndex has a defaultValue that's dependent on element itself. It's currently defined on a mixin so this wouldn't work. It's even based on where the summary element is in the DOM so I don't think this could be handled by IDL. (Potentially we could use [Reflect] and then just override the defaultValue using spec prose, but that would require we keep the default value concept in prose.) (Uses ReflectSetter to handle the simple setter case)

  • Various document IDL attributes reflect content attributes from the body element (or use an empty string if it's a frameset) so again that couldn't be defined in IDL.

The above is just some examples of what I've found, there's also the element internals cases that I haven't looked into yet and might need extra IDL or might not be doable.

- Swap code for span
- Add var to clampedMin and clampedMax
- Correct plural
This is used to apply the reflection code only for the setter.
… attribute, otherwise an integer, also clean up the single double usage to actually use a decimal.
@lukewarlow
Copy link
Member Author

Hopefully some of these changes improve the clarity of the definitions. I've also added a [ReflectSetter] as it turns out WebKit already has it and it cuts down on a number of basic setters.

@domenic
Copy link
Member

domenic commented Jul 17, 2025

I don't know that we'll ever be able to fully get rid of spec prose for reflection, but it might be that the end situation has few enough special cases that their prose should just be rewritten to not mention reflection and then we could drop many of these existing concepts.

I was more hopeful that we'd be able to get rid of the spec prose. After your change, the only normative references I see to "reflect" are enumerated attributes, and the ones you list as not possible with IDL. But, see below for how keeping it might be the best way to make some of the existing cases more rigorous.

My other hesitation along the same lines is I don't know what other specs use these algorithms. I didn't want to accidentally break URL reflection from another spec by removing the prose concept (though I'll admit it's rather vague at the moment so it's ideal anyway).

Personally, I think we should not be hesitant about breaking other such specs. The only other specs that should be using these concepts are:

  • MathML and SVG. (But from what I recall, these are not very good about defining reflection rigorously.)
  • Monkeypatch specs that are intended to one day go into HTML. These need to deal with upstream breakage all the time.

I think my preference would be to write them in terms of the existing prose initially and then once we've moved everything across (including looking at other specs). We can possibly rewrite how they're defined to drop the old approach. It would be purely editorial (I guess normative because we're removing existing algorithms?).

I think this is fair.

Even if we keep some prose concepts, I think it'd be nicer to clean up as much of the "public API" as possible. For example, getting rid of definitions like "default value" or "as a URL" or "limited to only non-negative numbers" and say that if you want those behaviors, you have to just use the extended attributes. (This could be done by having the algorithm steps inspect the reflected IDL attribute, instead of taking arguments.)

One other question is are we aiming to go for 100% coverage in IDL. Or is it okay if we end up with some still defined manually.

In my opinion, it's definitely fine to end up with some defined manually. I think the way they currently abuse "reflect" is not rigorous, and rewriting them to just be manual might be better. Or maybe the best road here is to figure out ways to define them rigorously using the prose concepts that underlie the extended attributes. (E.g., defining custom "get the element" algorithms for Document might be enough to rigorize those attributes.)

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

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

This looks good to me and I'd be OK merging it as-is.

One more potential point for discussion: we could automatically lowercase the name, to remove many cases where you need to provide it. E.g. instead of [Reflect="datetime"] attribute DOMString dateTime, we could just do [Reflect] attribute DOMString dateTime.

I kind of like the current explicitness, but on the other hand maintaining such cases is just kind of busywork for everyone, and maybe we should make it automatic. Then the string-taking versions is reserved for truly-exceptional cases.

<p>The <code data-x="xattr-ReflectDefault">[ReflectDefault]</code> <span>extended attribute</span>
must only be used on attributes with a type of <code data-x="idl-double">double</code>, <code
data-x="idl-long">long</code>, or <code data-x="idl-unsigned-long">unsigned long</code>. When used
on an attribute of type <code data-x="idl-double">double</code>, it must take a decimal, otherwise
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
on an attribute of type <code data-x="idl-double">double</code>, it must take a decimal, otherwise
on an attribute of type <code data-x="idl-double">double</code>, it must take a decimal; otherwise


<p>IDL attributes with the <code data-x="xattr-ReflectDefault">[ReflectDefault]</code>
<span>extended attribute</span> have a <span>default value</span> provided by <code
data-x="xattr-ReflectDefault">[ReflectDefault]</code>.</p>
Copy link
Member

Choose a reason for hiding this comment

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

Provided by "the argument provided to" [ReflectDefault], or something like that?

@lukewarlow
Copy link
Member Author

Ah yeah the lowercasing was something I'd thought of too forgot to comment about it, it seems webkits does that automatically at the very least. I think I lean towards doing it automatically just because it cuts down on noise and then the string case as you say can be for stuff where it's genuinely a different name (think encoding reflecting enctype or I think there's some hyphenated ones dotted about)

@lukewarlow lukewarlow marked this pull request as ready for review July 17, 2025 08:51
@lukewarlow
Copy link
Member Author

@annevk or @domenic am I okay to mark this as supportive from a browser implementor perspective or would you rather I file standards positions?

@domenic
Copy link
Member

domenic commented Jul 18, 2025

Since this has no normative impact, there's no need for browser support, just spec editor support.

Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

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

Very nice cleanup overall. Looking forward to see where this leads us.


<p>For one of these primary reflection <span data-x="extended attribute">extended
attributes</span>, its <span>reflected content attribute name</span> is the string value it takes,
if one is provided, or the IDL attribute name otherwise.</p>
Copy link
Member

Choose a reason for hiding this comment

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

converted to ASCII lowercase?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah this is something Domenic mentioned and I think it's probably right to handle that automatically. Cuts down on the number of manual references needed quite a bit.

attribute</span> must <span>reflect</span>, <span>limited to only positive numbers with
fallback</span>, <code
data-x="xattr-ReflectPositiveWithFallback">[ReflectPositiveWithFallback]</code>'s <span>reflected
content attribute name</span></p>
Copy link
Member

Choose a reason for hiding this comment

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

Missing dot.

Comment on lines +20245 to +20246
};</code></pre> <p class="note">The <code>HTMLQuoteElement</code> interface is also used by the
<code>q</code> element.</p>
Copy link
Member

Choose a reason for hiding this comment

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

Wrapping doesn't make sense here.

Comment on lines +20557 to +20558
<p class="note">The <span data-x="xattr-ReflectDefault">[ReflectDefault]</span> means that the
<code data-x="dom-ol-start">start</code> IDL attribute does not necessarily match the list's <span
Copy link
Member

Choose a reason for hiding this comment

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

Due to [ReflectDefault] the start IDL attribute ...

[<span>CEReactions</span>, <span data-x="xattr-Reflect">Reflect</span>] attribute USVString <dfn attribute for="HTMLSourceElement" data-x="dom-source-srcset">srcset</dfn>;
[<span>CEReactions</span>, <span data-x="xattr-Reflect">Reflect</span>] attribute DOMString <dfn attribute for="HTMLSourceElement" data-x="dom-source-sizes">sizes</dfn>;
[<span>CEReactions</span>, <span data-x="xattr-Reflect">Reflect</span>] attribute DOMString <dfn attribute for="HTMLSourceElement" data-x="dom-source-media">media</dfn>;
[<span>CEReactions</span>, <span data-x="xattr-Reflect">Reflect</span>] attribute unsigned long <dfn attribute for="HTMLIFrameElement,HTMLEmbedElement,HTMLObjectElement,HTMLSourceElement,HTMLVideoElement" data-x="dom-dim-width">width</dfn>;
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't make sense to me. We shouldn't <dfn> width for all these elements on this interface. Let's just give each its own width (and height) definition. Not sure what to do with dom-dim-width though. Perhaps that should be in the original section where it was once defined or maybe reused for one of these?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah keeping the IDs was the main reason I did it this way.

Copy link
Member

Choose a reason for hiding this comment

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

But then just keep it the same on one of them, but the others need to have their own definition I think. Sharing a definition made sense when they all pointed to a shared description. But pointing from one IDL attribute to another on a different interface makes little sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants