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?

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
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy