[Platform-provided behaviors for CE] Address feedback, add alternative to main proposal#1340
Conversation
Apply feedback from WHATWG #12150 and from multiple internal review rounds across the main explainer's User-facing problem, User research, Dynamic behaviors, Alt API design 3, and HTMLSubmitButtonBehavior Properties sections. Add Alt API design 5 (standard-defined strings) covering the shapes raised in WHATWG #12150. Move Behavior composition and conflict resolution into Future work. Replace prescriptive attachInternals() lifecycle guidance with neutral language. Cut duplicate examples and convert the Behavior lifecycle table to prose. Add htmlbuttonbehavior-with-type-attribute.md, a side document exploring an alternative direction that collapses the three button modes (submit, reset, generic-button) into a single HTMLButtonBehavior whose type property mirrors native <button>'s type attribute, and declares behaviors via a static class property (symmetric with static formAssociated) with platform-owned instantiation. Authors look up the platform-created instance through internals.behaviors.get(HTMLButtonBehavior). Net contribution vs. upstream/main: 2 files, +358 / -236.
dcf7800 to
9708740
Compare
`HTMLButtonElement`'s IDL adds form-control properties on top of `HTMLElement` but does not override `title`, `tabIndex`, `hidden`, `lang`, `dir`, `accessKey`, or `draggable`. All of these are pure `HTMLElement` surface that custom elements already inherit. Including `title` in the behavior interface would be redundant and would imply the behavior is involved in tooltip surfacing when it is not. Drop `title` from the Properties lists in both the main explainer (`HTMLSubmitButtonBehavior`) and the type-attribute alternative (`HTMLButtonBehavior`). Add a short note after each list pointing out that `HTMLElement`-inherited properties work directly on the host without behavior involvement.
| | `attachInternals()` called with behaviors | Each behavior is attached. Event handlers become active. Default ARIA role is applied unless overridden by `ElementInternals.role`. | | ||
| | Element disconnected from DOM | Behavior state is preserved. Event handlers remain conceptually attached but inactive. | | ||
| | Element reconnected to DOM | Event handlers become active again. Behavior state (e.g., `formAction`, `disabled`) is preserved. | | ||
| Calling `attachInternals()` with behaviors adds each behavior's event handlers and the default ARIA role is applied. Disconnecting the element from the DOM leaves event handlers attached but suspends them, while behavior state (`formAction`, `disabled`, etc.) is preserved. Reconnecting reactivates event handling against the preserved state. |
There was a problem hiding this comment.
| Calling `attachInternals()` with behaviors adds each behavior's event handlers and the default ARIA role is applied. Disconnecting the element from the DOM leaves event handlers attached but suspends them, while behavior state (`formAction`, `disabled`, etc.) is preserved. Reconnecting reactivates event handling against the preserved state. | |
| Calling `attachInternals()` with behaviors adds each behavior's event handlers and the ARIA associated with that behavior is applied. Disconnecting the element from the DOM leaves event handlers attached but suspends them, while behavior state (`formAction`, `disabled`, etc.) is preserved. Reconnecting reactivates event handling against the preserved state. |
The suggested change tries to clarify what "default role" means here.
gregwhitworth
left a comment
There was a problem hiding this comment.
Non-blocking comments primarily but I am curious about the other proposal and which one we ultimately want to put forward so keeping this at a "comment" phase so we can debate if necessary
| ### Developer-defined behaviors | ||
|
|
||
| This direction is explored in a separate document: [Developer-defined behaviors](developer-defined-behaviors.md). It is not part of the current proposal and should be treated as forward-looking exploration. | ||
| A future extension of this proposal could allow developers to define their own reusable behaviors by subclassing an `ElementBehavior` base class. This would enable patterns like polyfilling upcoming platform behaviors and composing developer-defined behaviors with platform-provided ones. This direction is explored in a separate document: [Developer-defined behaviors](developer-defined-behaviors.md). It is not part of the current proposal and should be treated as forward-looking exploration. |
There was a problem hiding this comment.
I'm curious what others think but I don't want to bring this up in this proposal. Let that proposal stand on its own once we know developers need it and this aspect has landed.
|
|
||
| ### HTMLButtonBehavior | ||
|
|
||
| This alternative introduces `HTMLButtonBehavior`, which mirrors native `<button>`. The behavior has a `type` property (`'submit'`, `'reset'`, or `'button'`, defaulting to `'submit'`) that selects the active button mode. The `type` is mutable for the life of the behavior. |
There was a problem hiding this comment.
It's a little unclear what HTMLButtonBehavior is in this version. It seems like it's not instantiable here, right? And it maybe doesn't have any properties of its own, it's more of a special marker type?
Also worth pointing out that we could do more of a hybrid approach where we do everything the way it is in the approach in the main explainer, but instead of HTMLSubmitButtonBehavior we have HTMLButtonBehavior with a dynamic type that can support button/submit/reset.
There was a problem hiding this comment.
Reading further, I guess HTMLButtonBehavior is the class of the object that will get added to the behaviors array? So it'll be like this?
class CustomButton extends HTMLElement {
static formAssociated = true;
static behaviors = [HTMLButtonBehavior];
#internals;
constructor() {
super();
const buttonBehavior = this.#internals.behaviors.get(HTMLButtonBehavior);
buttonBehavior instanceof HTMLButtonBehavior; // true
}
}
new HTMLButtonBehavior(); // is this still allowed?
Updates
Main explainer
<button type="submit">as a single-element conformance target that exercises every part of the framework.attachInternals()lifecycle:attachInternals()can be called from the constructor,connectedCallback, orattributeChangedCallback, depending on whether attributes are set before or after construction.HTMLSubmitButtonBehaviorships initially; composition becomes relevant once additional behaviors land).HTMLSubmitButtonBehaviorproperties: Addedtitlewith a note that it surfaces through the user agent's default tooltip UI. Removed theattributeChangedCallbackexample.New alternative
New file:
PlatformProvidedBehaviors/htmlbuttonbehavior-with-type-attribute.md. Side document exploring an alternative:HTMLButtonBehaviorwhosetypeproperty mirrors thetypeattribute of native<button>and toggles the active mode at runtime.static behaviorsclass property. The platform instantiates each declared behavior at element creation; authors look up the instance throughinternals.behaviors.get(HTMLButtonBehavior).