08:20
<Noam Rosenthal>

I've made a rough refinement proposal to the platform provided behahviors after the hackfest WHATNOT, I wonder what people think
https://github.com/MicrosoftEdge/MSEdgeExplainers/issues/1353

(e.g. keithamus Luke Warlow might be interested)

08:23
<Noam Rosenthal>
Tl;dr is to have activationBehavior and potentially other discrete "types" of behavior in the future. Different types of behavior can compose with each other, but each type has its own notion of what's mutually exclusive (e.g. link and button are two mutually exclusive activation behaviors)
08:37
<keithamus>
A similar proposal was raised by microsoft around... 2023 TPAC maybe? I am personally against the idea of static members. I don't think they're very readable, I think string values are messy and easy to make mistakes with (and silently fail if you typo either the name or the value). This also doesn't represent the same semantics as the proposed elementinternals, which is that this isn't then switchable at runtime.
08:37
<Noam Rosenthal>
The static vs. attaching as internal thing is not the main idea
08:38
<keithamus>
The main idea is the concept of a activationBehavior?
08:38
<Noam Rosenthal>
Yes, the concept that behaviors are clustered by type rather than in a general purpose array
08:38
<Noam Rosenthal>
I'm OK with attaching them in runtime, e.g. only when an element is disconnected or with some other constraint or whatever
08:38
<keithamus>
So we go from 1 vector member to N scalar members?
08:40
<Noam Rosenthal>
For now, 1 scalar member (activation), and every increase in N is speced
08:40
<keithamus>
What shape is ElementInternals.prototype.activationBehavior in this case? It seems it would have to be a superset of all possible activation behaviours? i.e. it needs href, formAction and so on? What if I set activationBehavior = 'link' then set internals.activationBehavior.formAction = 'POST'? I guess nothing happens?
08:43
<Noam Rosenthal>

We can bikeshed on that but if it was static I think activationBehavior can return a LinkBehavior interface etc. we can find a shape for it if it's not static, e.g.

internals.activationBehavio.setLink({href: "/example"});
internals.activationBehavior.setSubmit({formData: "POST"});
08:43
<keithamus>
I'm curious - as a thought experiment, how would you solve this in C++? Like if I said to you "we have HTMLButtonElement, we have HTMLLinkElement, we need a new element which is sometimes a button and sometimes a link", what would be the general shape to solve this?
08:44
<Noam Rosenthal>
std::variant<HTMLButtonElement, HTMLLinkElement> ?
08:44
<Noam Rosenthal>
Or an interface that both implement (old school polymorphism)?
08:45
<Noam Rosenthal>
A variant/union is a very established concept
08:45
<keithamus>
I imagine I would move their activation behaviours into a mixin, and have them both apply their respective mixins, then have the new element call one or the other.
08:46
<Noam Rosenthal>
Yea sure, that's a different flavor of polymorphism
08:47
<keithamus>
At any rate; I don't want to make JS into C++, but it seems the solutions we have for C++ significantly diverge from the solutions we're proposing for JS.
08:48
<Noam Rosenthal>
I don't think so? how is activationBehavior: "submit" | "link" different from `std::variant<SubmitButton | LinkButton> behavior_`
08:49
<Noam Rosenthal>
When I develop this in C++ I could have multiple options but I would usually try to make the types statically reflect what's possible rather than have a bunch of runtime conflict resolution/error scenarios (which is what an array can lead to)
08:50
<keithamus>
Right but you don't do that by adding static members that assign/return strings, right?
08:51
<keithamus>
I can't help but feel like if JS had some better intrinsics (i.e. mixins) we perhaps wouldn't be having this conversation, because the solution would be more apparent.
08:51
<Noam Rosenthal>
The "effective type" of a variant is an enum, and enum in JS is a string
08:52
<Noam Rosenthal>
Also C++ doesn't really have mixins. You can do multiple inheritance but that's considered something you need to be very careful with
08:54
<Noam Rosenthal>
Anyway I think we can solve the issue people have with providing platform-like behaviors (specifically button/link-like) to their own custom elements without having to invent new language features
08:54
<keithamus>
Why is the effective enum in JS a string? Most languages its a number, and a lot of the older DOM code has numeric enums, with static const aliases.
08:56
<keithamus>
FTR I'm not advocating for associatedBehaviour = 1 any more than "button". I think both have all the same problems; which are second-order to the variant issue. Namely, that we can't really throw or tell the developer they got this wrong if it's a static member. If it's not a static member though, you inherit all of the runtime difficulty you're wanting to move away from.
08:56
<Noam Rosenthal>
Because as an interpreted language, strings in JS are not more expensive than constant numbers. And they're much easier to extend than numeric enums
08:59
<Noam Rosenthal>
const submitBehavior = new SubmitBehavior();

// Throws if element is connected
element.internals.activation = submitBehavior;
submitBehavior.formAction = "POST"
08:59
<keithamus>
I'm also not suggesting we invent new language features. More just lamenting at the current state of JS, I suppose. Like for example if decorators were actually shipping in JS engines, I'd imagine there'd be some proposal around built-in decorators for this.
08:59
<Noam Rosenthal>
Yea I think I never liked either mixins or decorators TBH. They both create an implicit processing model. But it's a matter of taste
09:01
<Noam Rosenthal>
If people want to develop in that kind of way in user space it's fine, but I think that as the platform we can be more conservative and provide the minimum needed functionality in a concise way. What I don't understand yet is why and how those behaviors need to be composed with user-defined behaviors and are they even on the same dimension
09:04
<keithamus>
I think providing a mechanism that users can build their own in userland helps developers understand how the feature works, and also means there's less gymnastics when it comes to polyfills, which helps with feature adoption.
09:06
<Noam Rosenthal>
Polyfills aside, I get that sort of conceptually but none of the explainers show how this works in practice and I fail to understand how putting platform behaviors in an open-ended array helps users build their own behaviors in userland.
09:07
<Noam Rosenthal>
It also does not explain how the platform works - because it creates a bunch of error conditions that you need to read the spec to understand
09:07
<Noam Rosenthal>
In the platform you likely have only one activation behavior, so allowing you to put several in an array un-explains it
09:08
<keithamus>
I don't disagree but I think the array came from the idea that developers will combine behaviours, e.g. the button/link case.
09:11
<Noam Rosenthal>
behaviors are still combinable here, e.g. activation and replaced-content can be separate behaviors. Then we can decide if "link" is mutually exclusive from button or not, and then it can be "buttonBehavior" and "linkBehavior" (what happens when you click it though?). I think allowing a "link-button" in one element is more harm than good but I can be persuaded otherwise
09:13
<Noam Rosenthal>
If the platform can safely provide a "button link" by combining those two behaviors, then absolutely they should be composed in this API. My impression from the use cases is that this type of composability is more of a neat idea than something that's actually sought out
09:35
<Noam Rosenthal>
https://github.com/whatwg/html/pull/12642
09:36
<Lea Verou>
Ugh, thanks Element for not notifying me about all these responses. :(
09:38
<Lea Verou>

I don't think it makes sense to design individual web platform features to be polyfillable, but I think it's defensible as a goal that the platform should provide the low-level primitives that make polyfilling viable a whole. There are gaps that affect both polyfills occupying the same namespace or ponyfills. For example:

  • CSS polyfills currently require refetching and reparsing the entire stylesheet, making individual polyfills effectively unviable
  • HTML polyfills that work correctly across shadow DOM boundaries are practically impossible to implement performantly because of the lack of hooks to monitor (even open) shadow roots, monitor mutations across shadow roots, or fetch elements that match a certain pattern across shadow roots.
09:40
<Luke Warlow>
FTR I'm not advocating for associatedBehaviour = 1 any more than "button". I think both have all the same problems; which are second-order to the variant issue. Namely, that we can't really throw or tell the developer they got this wrong if it's a static member. If it's not a static member though, you inherit all of the runtime difficulty you're wanting to move away from.
Just to re-iterate the current design doesn't solve essentially any of the runtime 'issues' and I think they're exaggerated.
09:40
<Lea Verou>
I can see the argument that polyfills may reduce motivation for browsers to implement a feature natively, but polyfills also encourage authors to use a standardized feature, which increases motivation for browsers to implement. I don't think it's clear-cut which of these forces prevails in the end, but historically I'd say polyfills have helped drive implementations rather than discourage them.
09:42
<Luke Warlow>
Fwiw I still lean towards a truly dynamic rather than static or one time dynamic system
09:44
<Lea Verou>
Ponyfills are helpful, especially for cases where they can be close enough to the final API ergonomics (the <element> vs <foo-element> example mentioned above). But their appeal is weaker. The core appeal of polyfills is that you can use a modern feature in browsers that support it, with the benefits of performance, correctness, etc. and you can later simply remove the scaffolding and you're left with something that works. If you lose that promise, the benefit is unclear. You may as well just use a userland library which has fewer constraints and moves faster.
09:49
<Lea Verou>
I agree that sometimes speculative polyfills have jumped the gun, but even then, the risks of authors experimenting with a speculative API using a polyfill are far smaller than browsers shipping the API only to later find that it doesn't cater to author needs to the extent that was anticipated. JS has always allowed polyfills with absolutely no restrictions on namespace, and historically cases like smooshgate or the more recent scoped registries one are still few and far between, and IMO do not outweigh the benefits the platform got in the same timeframe from the existence of polyfills as a whole.
09:50
<Noam Rosenthal>
Yea none of this change is opinionated about dynamism/mutability. I don't have a strong opinion on that. I suggested "only change when disconnected" but it's orthogonal
09:56
<Lea Verou>

I would much rather people write a library that demonstrates the need for something

I see "library that implements some feature" and "polyfill" as synonymous, but I can also see that fails to capture everything.

The psychology of the two is completely different. One is introducing another dependency and all the risk-benefit and comparative evaluation that comes with that. The other is simply bridging a gap temporarily, with the intent of being removed later. You're no longer need to evaluate whether an API meets your needs, and can swap one implementation for another with no integration effort. Basically, you get the API benefits of standardization, even before you get the implementation benefits.

10:01
<Lea Verou>

Anyhow, my takeaway from reading this discussion (and from some private discussions over the last few days) is:

  • it does not appear to be committee consensus that pollyfills are undesirable though we recognize it's a tradeoff and not without costs
  • there are some views that ponyfills might be a better solution
  • speculative polyfills of still in-design APIs are have a worse cost-benefit than polyfills of mature features
  • it's less clear to what extent we consider making their existence possible a standards goal.

Please correct me if you feel this is inaccurate.

10:09
<Noam Rosenthal>
https://github.com/whatwg/html/pull/12643
14:25
<annevk>
Shannon Booth: so https://github.com/whatwg/html/pull/12624 works, right? I'll do another round of editorial review.
15:11
<Noam Rosenthal>
Actually I think I spotted something when I worked on the follow up - we need to adjust to the root insertion target also when inserting non-elements. So I'll make that revision together with the editorial changes
16:00
<Noam Rosenthal>
Shannon Booth: I wonder how this didn't come up in testing
16:01
<Noam Rosenthal>
(side note: I love that ladybird even gives us this testing ability in the first place)
17:04
<mfreed>
Hi all, just a friendly reminder to post any discussion topics for NEXT Thursday's joint CSSWG/WHATWG/OpenUI task force meeting to the meeting agenda issue: https://github.com/whatwg/html/issues/12620 (I'm sending this a week early, because I'm out next week.)
17:06
<Noam Rosenthal>
OK should be good now (also fixed nits)
17:37
<Shannon Booth>
Oops! This bit of the parser didn't match the spec very closely (and is quite close to FFI glue), so I probably just missed some portions where it was adjusting the position where the spec wasn't. Also possible the coverage I was running didn't catch it perhaps
17:44
<Shannon Booth>
But yeah, works well, hopefully also helps with the sanitiser stuff
18:17
<Shannon Booth>
Though from auditing some WPTs, I do suspect there are some other issues. For example, looks like the fragment parser for the outer HTML setter might need to be passed the element which is created rather than parent based on https://github.com/web-platform-tests/wpt/blob/master/html/webappapis/dynamic-markup-insertion/the-outerhtml-property/outerhtml-documentfragment.html Seems unrelated to these improvements though