You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Updates:
- Deleted paragraph on "behavior" vs "mixins". Will wait for more feedback on naming.
- Updated API shape to access attributes/properties.
- Added example to explore declarative version further.
- Added clarification and example workaround for dynamic attribute/mixins changes.
- Expanded section on the (future) possibility of conflicting mixins being used together and strategies to mitigate conflicts.
-`ElementInternals` instances expose a read-only `mixins` property returning the list of attached behaviors.
90
90
- Supports composition as web authors can pass many behaviors.
91
91
92
-
*Note: The API uses the term "mixins" instead of "behaviors" to avoid potential confusion with the spelling of "behavior" vs "behaviour".*
93
-
94
92
### Platform-Provided Behavior Mixins
95
93
96
94
The platform would expose the following behavior mixin, mirroring the submission capability of `HTMLButtonElement`:
@@ -110,7 +108,7 @@ Each platform behavior mixin must provide:
110
108
111
109
Platform-provided mixins expose useful public properties and methods of their corresponding native elements. Authors can expose these capabilities on their custom element's public API by defining accessors that delegate to the mixin state.
112
110
113
-
These APIs are accessed via specific properties on `ElementInternals` (e.g., `htmlSubmitButtonMixinState`). This property provides a direct interface to the underlying platform behavior managed by the mixin. It returns a non-null state object only if the corresponding mixin is passed to `attachInternals`.
111
+
These APIs are accessed via the `mixins` property on `ElementInternals`. This property provides access to their instance-specific state via properties named after the mixin.
114
112
115
113
For `HTMLSubmitButtonMixin`, the state object exposes the following properties found on [`HTMLButtonElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement):
116
114
@@ -134,33 +132,40 @@ class CustomSubmitButton extends HTMLElement {
This ensures developers don't have to reimplement the state logic that the mixin is supposed to provide.
152
+
This ensures web authors don't have to reimplement the state logic that the mixin is supposed to provide.
155
153
156
154
### Composition via attachInternals
157
155
158
156
Passing behaviors to `attachInternals()` provides several advantages for web component authors:
159
157
160
158
- Behaviors are defined once during initialization, avoiding the complexity of managing behavior lifecycle (adding/removing) and state synchronization.
161
159
- Authors can define a single class that handles multiple modes (submit, reset, button) by checking attributes before attaching internals, without needing to define separate classes for each behavior.
162
-
- While this proposal focuses on an imperative API, the underlying model of attaching mixins via `ElementInternals` is compatible with future declarative APIs.
163
160
- A child class extends the parent's functionality and retains access to the `ElementInternals` object and its active mixins, allowing for standard object-oriented extension patterns.
161
+
- While this proposal uses an imperative API, the design supports future declarative custom elements. Once a declarative syntax for `ElementInternals` is established, attaching mixins could be modeled as an attribute, decoupling behavior from the JavaScript class definition. Platform-provided mixins could be referenced by string identifiers in markup. The following snippet shows a hypothetical example of declarative usage and how platform-provided mixins could be attached via an attribute.
- Ability to inspect its own behaviors via `this._internals.mixins`.
242
+
- Ability to inspect its own properties via `this._internals.mixins`.
243
+
244
+
*Note: In this proposal, the set of mixins is fixed when `attachInternals` is called. If the `type` attribute changes later, the element cannot dynamically swap mixins on the existing instance. To support dynamic type changes, web developers create a fresh instance of the element (which hasn't called `attachInternals` yet) with the new attribute and replace the old instance.*
245
+
246
+
```javascript
247
+
attributeChangedCallback(name, oldVal, newVal) {
248
+
// Only recreate if we've already initialized (mixins are locked).
249
+
if (name ==='type'&&this._internals) {
250
+
// Create a fresh instance. It hasn't run connectedCallback yet,
// The new instance will read this 'type' during its initialization.
256
+
replacement.setAttribute('type', newVal);
257
+
258
+
// Swap the old element with the new one.
259
+
// This triggers connectedCallback() on the new instance, allowing it
260
+
// to call attachInternals() with the new mixin set.
261
+
this.replaceWith(replacement);
262
+
}
263
+
}
264
+
```
238
265
239
266
## Future Work
240
267
@@ -248,7 +275,13 @@ While this proposal focuses on form submission, the mixin pattern can be extende
248
275
-**Radio Groups**: `HTMLRadioGroupMixin` for `name`-based mutual exclusion.
249
276
-**Tables**: `HTMLTableMixin` for table layout semantics and accessibility.
250
277
251
-
*Conflict Resolution: As the number of available mixins grows, we must address how to handle collisions when multiple mixins attempt to control the same attributes or properties. We propose that the order of mixins in the array passed to `attachInternals` should determine precedence (e.g., last one wins), but specific heuristics for complex clashes need to be defined.*
278
+
### Conflict Resolution
279
+
280
+
As the number of available mixins grows, we must address how to handle collisions when multiple mixins attempt to control the same attributes or properties. We should explore several strategies to make composition possible without getting unexpected or conflicting behaviors:
281
+
282
+
1.**Order of Precedence (Default)**: The order of mixins in the array passed to `attachInternals` determines precedence (e.g., "last one wins"). This is simple to implement but may hide subtle incompatibilities.
283
+
2.**Compatibility Allow-lists**: Each mixin could define a short list of "compatible" mixins that can be used in combination. Any combination not explicitly allowed would be rejected by `attachInternals`, preventing invalid states (like being both a button and a form).
284
+
3.**Explicit Conflict Resolution**: If conflicts occur, the platform could require the author to explicitly alias or exclude specific properties.
While customized built-ins are useful where supported, the issues listed above makes them unsuitable as the primary solution.
435
468
436
-
### Alternative 5: Expose certain behavioural attributes via ElementInternals (Proposed)
469
+
### Alternative 5: Expose certain behavioral attributes via ElementInternals (Proposed)
437
470
438
471
Expose specific behavioral attributes (like `popover`, `draggable`, `focusgroup`) via `ElementInternals` so custom elements can adopt them without exposing the attribute to the user. See [issue #11752](https://github.com/whatwg/html/issues/11752).
439
472
@@ -484,7 +517,7 @@ While valuable, this can be a parallel effort. Even if all native elements were
484
517
485
518
### Browser Vendors
486
519
487
-
- Chromium: No signal
520
+
- Chromium: Positive
488
521
- Gecko: No signal
489
522
- WebKit: No signal
490
523
@@ -498,6 +531,7 @@ Many thanks for valuable feedback and advice from:
0 commit comments