Skip to content

[Platform-provided behaviors for CE] Address feedback, add alternative to main proposal#1340

Open
anaskim wants to merge 2 commits into
MicrosoftEdge:mainfrom
anaskim:platform-provided-behaviors-mutability-lifecycle
Open

[Platform-provided behaviors for CE] Address feedback, add alternative to main proposal#1340
anaskim wants to merge 2 commits into
MicrosoftEdge:mainfrom
anaskim:platform-provided-behaviors-mutability-lifecycle

Conversation

@anaskim

@anaskim anaskim commented Jun 9, 2026

Copy link
Copy Markdown
Member

Updates

Main explainer

  • User-facing problem: Promote the form-control pseudo-class set and the native focusability algorithm into the reimplementation bullet.
  • User research: Reframe the closing paragraph around <button type="submit"> as a single-element conformance target that exercises every part of the framework.
  • Dynamic behaviors: Add set / state / participation at the start of the section.
  • attachInternals() lifecycle: attachInternals() can be called from the constructor, connectedCallback, or attributeChangedCallback, depending on whether attributes are set before or after construction.
  • Alt API design 3: Open questions resolved; the recomputation table collapsed into a single sentence pair.
  • Behavior composition and conflict resolution: Moved out of the main proposal area into Future work (only HTMLSubmitButtonBehavior ships initially; composition becomes relevant once additional behaviors land).
  • HTMLSubmitButtonBehavior properties: Added title with a note that it surfaces through the user agent's default tooltip UI. Removed the attributeChangedCallback example.
  • Trimming and fixes: Cut duplicate examples in Accessing behavior state, API design, Conflicting behaviors, and Other considerations. Folded "Why start with form submission?" into the Introduction. Converted the Behavior lifecycle table to a paragraph. Fixed an invalid optional-chaining assignment in the opening Proposed approach example.

New alternative

New file: PlatformProvidedBehaviors/htmlbuttonbehavior-with-type-attribute.md. Side document exploring an alternative:

  1. Collapses the three button modes (submit, reset, generic-button) into a single HTMLButtonBehavior whose type property mirrors the type attribute of native <button> and toggles the active mode at runtime.
  2. Declares behaviors via a static behaviors class property. The platform instantiates each declared behavior at element creation; authors look up the instance through internals.behaviors.get(HTMLButtonBehavior).

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.
@anaskim anaskim force-pushed the platform-provided-behaviors-mutability-lifecycle branch from dcf7800 to 9708740 Compare June 9, 2026 17:59
@anaskim anaskim requested a review from dandclark June 9, 2026 18:12
@anaskim anaskim marked this pull request as ready for review June 9, 2026 18:12
@anaskim anaskim requested a review from leotlee June 9, 2026 18:12
`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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
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 gregwhitworth left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Comment thread PlatformProvidedBehaviors/explainer.md
Comment thread PlatformProvidedBehaviors/explainer.md
### 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread PlatformProvidedBehaviors/htmlbuttonbehavior-with-type-attribute.md
Comment thread PlatformProvidedBehaviors/explainer.md

### 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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants