Skip to content

Conversation

@anaskim
Copy link
Contributor

@anaskim anaskim commented Dec 12, 2025

V1 includes:

  • Rewording on interoperability.
  • Adds examples on current workarounds used by frameworks.
  • Adds goal to clarify the general and specific objectives of the proposal.
  • "behavior" -> "mixin", to avoid confusion with "behaviour" spelling.
  • Simplifies to add mixins to attachInternals() and avoid dynamic changes at runtime.
  • Adds mixins property to ElementInternals to query behaviors.
  • Removed "Open questions" section and expanded "Future Work" section with a "collision handling" note and 2 more proposed mixins (input and table behaviors).
  • Updated "Accessibility, Security, and Privacy Considerations" section.
  • Updated acknowledgements.

@anaskim anaskim marked this pull request as ready for review December 12, 2025 21:47
Copy link
Contributor

@mhochk mhochk left a comment

Choose a reason for hiding this comment

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

Looks ready for wider-web discussion to me 👍

Copy link
Member

@dandclark dandclark left a comment

Choose a reason for hiding this comment

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

I think this is a promising direction. I like that it addresses the feedback about composability and that it would allow things like <custom-button type=submit> to work.

The main thing that's unclear to me is whether this approach still causes the custom element to sprout attributes and properties associated with the set of supported behaviors when a mixin is added.
I think that's implied but that aspect isn't as clearly laid out as in https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/ElementInternalsType/explainer.md. Could it be stated more explicitly?

Copy link
Contributor Author

@anaskim anaskim left a comment

Choose a reason for hiding this comment

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

Thanks for the feedback! I added a paragraph in the Platform-Provided Behavior Mixins section to address the exclusion of attributes and properties with mixins in this proposal. Open to changing if I get feedback from web devs saying they would expect them to be included though.

- Event handling: Automatic wiring of platform events (click, keydown, etc.)
- ARIA defaults: Implicit roles and properties for accessibility.

Attaching a behavior mixin provides internal platform capabilities but does not automatically add the corresponding properties (like `disabled`, `value`, or `formAction`) or attributes to the custom element. The web component author is responsible for defining these properties and attributes to expose this state to users of the element.
Copy link
Member

@dandclark dandclark Jan 8, 2026

Choose a reason for hiding this comment

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

Not blocking for releasing this explainer, but omitting support for the properties raises some questions about how devs would manually define these in practice.

For example, with an HTMLInputMixin, what would be the way to access the value of the control? The author of the control can expose a value property manually, but where does it get the underlying value to return, or where can it set the control's internal value when the attribute is set? Something like this maybe?

    get value() {
        // assert: this.internals_.mixins[0] is a HTMLInputMixin
        return this.internals_.mixins[0].value;
    }

    set value(value) {
        // assert: this.internals_.mixins[0] is a HTMLInputMixin
        return this.internals_.mixins[0].value = value;
    }

Would this also be the way that methods like checkValidity() would be used?

class MyCustomInput extends HTMLElement {
    checkValidity() {
        // assert: this.internals_.mixins[0] is a HTMLInpuMixin
        return this.internals_.mixins[0].checkValidity();
    }
}

And maybe disabled would be set this way too?

class MyCustomButton extends HTMLElement {
    set disabled(isDisabled) {
        // assert: this.internals_.mixins[0] is a HTMLButtonMixin
        this.internals_.mixins[0].disabled = isDisabled;
    }
}

If there isn't a way to get at the "real" value of these properties then it seems like devs will still have to do significant work to reimplement a lot of this functionality.

Copy link
Member

Choose a reason for hiding this comment

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

Although I guess it couldn't work exactly this way, since this.internals_.mixins contains (I think) global/static HTMLInputMixin/HTMLButtonMixin etc objects, not an object associated with the specific instance of the control. So might need to invent a way to get to the internal versions of these attributes/properties/methods associated with the specific control instance. The old type proposal did this by having internals sprout another interface associated with the control instance: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/ElementInternalsType/explainer.md#example-1

```javascript
class MyCustomInput extends HTMLElement {
get value() {
return this._internals.getMixinState(HTMLInputMixin).value;
Copy link
Member

Choose a reason for hiding this comment

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

An alternative structure that could me more ergonomic would be to give ElementInternals properties for HTMLInputMixinState, etc, that would be non-null only if that mixin is passed to attachInternals. Then the example would look like:

class MyCustomInput extends HTMLElement {
   get value() {
       return this._internals.htmlInputMixinState.value;
   }

   checkValidity() {
       return this._internals.htmlInputMixinState.checkValidity();
   }
}

I observe though that this is kind of converging back towards the type proposal. Other than the use of the word "mixin", I guess the key differences are:

  • Applying the behaviors happens at attachInternals time, not statically, so different component instances can have different behaviors based on attributes or other state.
  • This new syntax allows for composition by taking an array of behaviors instead of a single type string.

Are these differences enough to meet the objections that "type" ran into?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah looks this close to an iteration of the .type proposal. I'm loosely basing this new one on this comment by Rob Eisenberg WICG/webcomponents#814 (comment). My general reading of the objections has been that the ElementInternals.type proposal had: "Magic" inheritance and too many vague/confusing things bundled together, in addition to some people not liking the static syntax. That's why I initially wanted to keep it as straight forward as possible and make the mixin very straightforward. I think the composition part is definitely a good point, but I wonder if we're going to get pushback for using ElementInternals instead of static class mixins (alternative 1 in the explainer).

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants