Skip to content

Commit dcf7800

Browse files
author
Ana Sollano Kim
committed
Trim explainer and rewrite type-attribute alternative
Tighten the main explainer's Properties section: remove the attributeChangedCallback example and the form-override mechanics table, both now redundant with the surrounding prose. Drop a few minor qualifiers ("directly", "each pinned to a single native pattern", "This proposal supports common web component patterns:") that were not adding signal. Rename the side document from htmlbuttonbehavior-with-type-toggle.md to htmlbuttonbehavior-with-type-attribute.md and rewrite it around the static class declaration model: - static behaviors = [HTMLButtonBehavior] declared at the class level, read at customElements.define() time, mirroring static formAssociated. - The platform instantiates behaviors at element creation; authors look up the instance through internals.behaviors.get(HTMLButtonBehavior). - HTMLButtonBehavior collapses submit, reset, and generic-button into a single behavior whose type property toggles the active mode at runtime. - Properties section generalized from submit-only to all three type values, with explicit qualifiers for type-conditional behavior. - Scenario table calls out commandfor/popovertarget short-circuit semantics matching native button. Outside-a-form and non-form-associated rows merged. - Invalid type values are silently coerced to the default state (submit), matching native button's invalid-value default. - Feature detection mirrors the main explainer's branch structure, translated to the static-declaration shape. - WebIDL stub removed; explainer voice keeps IDL out of scope (deferred to the design doc).
1 parent 97ab775 commit dcf7800

3 files changed

Lines changed: 267 additions & 380 deletions

File tree

PlatformProvidedBehaviors/explainer.md

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ This proposal introduces `HTMLSubmitButtonBehavior`, which mirrors the submissio
130130

131131
### Behaviors are not opaque tokens
132132

133-
A recurring concern about consolidating form-control semantics into an opt-in is that web authors will not be able to figure out what a given opt-in actually does. This proposal addresses that concern directly:
133+
A recurring concern about consolidating form-control semantics into an opt-in is that web authors will not be able to figure out what a given opt-in actually does. This proposal addresses that concern:
134134

135-
- Each element behavior maps to a single native pattern (e.g., `HTMLSubmitButtonBehavior` provides exactly the semantics of `<button type="submit">`). Future element behaviors will need to follow the same naming convention, each pinned to a single native pattern.
135+
- Each element behavior maps to a single native pattern (e.g., `HTMLSubmitButtonBehavior` provides exactly the semantics of `<button type="submit">`). Future element behaviors will need to follow the same naming convention.
136136
- Each behavior is specified in terms of existing HTML algorithms. The behavior is the union of those algorithms, applied to a custom element.
137137
- Web authors can override individual defaults. This already works today for role: `internals.role` overrides a behavior's default role without replacing the behavior. The same layering pattern can extend to other defaults (focusability, keyboard activation, and similar) if and when future proposals add the corresponding primitives on `ElementInternals`. The [layering example in Alternative 7](#alternative-7-low-level-primitives-on-elementinternals) walks through what that would look like.
138138

@@ -150,35 +150,12 @@ Each behavior exposes properties and methods from its corresponding native eleme
150150
- `formTarget`
151151
- `labels` - read-only, delegates to `ElementInternals.labels`
152152
- `name`
153-
- `title` - surfaced through the user agent's default tooltip UI, like native `<button>`.
153+
- `title` - surfaced through the user agent's default tooltip UI
154154
- `value`
155155

156-
To expose properties like `disabled` or `formAction` to external code, authors define getters and setters on the host that delegate to the behavior. See [Use case: Design system button](#use-case-design-system-button) for a complete worked example.
156+
To expose these properties to external code, authors define getters and setters on the host that delegate to the behavior. See [Use case: Design system button](#use-case-design-system-button) for a complete worked example.
157157

158-
Authors are responsible for attribute reflection. If the author wants HTML attributes on their custom element to affect the `behavior`, they need to observe and forward those attributes using `attributeChangedCallback`:
159-
160-
```javascript
161-
class CustomButton extends HTMLElement {
162-
static observedAttributes = ['disabled', 'formaction'];
163-
164-
attributeChangedCallback(name, oldValue, newValue) {
165-
if (name === 'disabled') {
166-
this._submitBehavior.disabled = newValue !== null;
167-
} else if (name === 'formaction') {
168-
this._submitBehavior.formAction = newValue ?? '';
169-
}
170-
}
171-
}
172-
```
173-
174-
Form override values (`formAction`, `formEnctype`, `formMethod`, `formNoValidate`, `formTarget`, `name`, `value`) are read from `behavior` properties. Setting a value declaratively in markup (e.g., `<my-button formaction="/save">`) or programmatically (e.g. `setAttribute('formaction', '/save')`) has no effect on form submission unless the author explicitly forwards that attribute to the `behavior`. However, some element attributes are applied to form submission as part of the existing [form-associated custom element](https://html.spec.whatwg.org/multipage/custom-elements.html#form-associated-custom-elements) mechanism, independently of behaviors:
175-
176-
| Element attribute | Applied via form-associated custom element mechanics | Notes |
177-
|-------------------|------------------------------------------------------|-------|
178-
| `form` | Yes | Standard form association by ID. `behavior.form` is read-only and delegates to `ElementInternals.form`, which reflects this association. |
179-
| `disabled` | Yes | Standard form control disabling. Combined with `behavior.disabled`. |
180-
| `name`, `value` | No | Only `behavior.name` and `behavior.value` are read on submission. |
181-
| `formaction`, `formenctype`, `formmethod`, `formtarget` | No | Only `behavior` properties are read. |
158+
Form override values (`formAction`, `formEnctype`, `formMethod`, `formNoValidate`, `formTarget`, `name`, `value`) are read from `behavior` properties. Setting a value declaratively in markup (e.g., `<my-button formaction="/save">`) or programmatically (e.g. `setAttribute('formaction', '/save')`) has no effect on form submission unless the author explicitly forwards that attribute to the `behavior`. However, some element attributes are applied to form submission as part of the existing [form-associated custom element](https://html.spec.whatwg.org/multipage/custom-elements.html#form-associated-custom-elements) mechanism.
182159

183160
### Behavior lifecycle
184161

@@ -259,8 +236,6 @@ if (typeof HTMLSubmitButtonBehavior !== 'undefined') {
259236
260237
### Other considerations
261238
262-
This proposal supports common web component patterns:
263-
264239
- Custom elements using behaviors can follow progressive enhancement patterns: use `<slot>` to render fallback content, provide `<noscript>` alternatives, and design markup to be readable without JavaScript. If script fails to load, the element receives no behavior, which is true for any autonomous custom element with or without this proposal.
265240
- Because behaviors are pinned to existing algorithms, this framework also enables polyfilling: authors can approximate new behaviors in *userland* before native support ships (see [Developer-defined behaviors](#developer-defined-behaviors) in [Future Work](#future-work)).
266241
- While this proposal uses an imperative API, the design supports future declarative custom elements. Once a declarative syntax for `ElementInternals` is established, attaching behaviors could be modeled as an attribute, decoupling behavior from the JavaScript class definition. The following snippet shows a hypothetical example:
@@ -755,7 +730,7 @@ While valuable, this can be a parallel effort. Even if all native elements were
755730
756731
### Alternative 7: Low-level primitives on ElementInternals
757732
758-
Expose individual primitives directly on `ElementInternals`. Authors compose every native capability piece by piece.
733+
Expose individual primitives on `ElementInternals`. Authors compose every native capability piece by piece.
759734
760735
**Pros:**
761736
- Maximum flexibility: authors compose exactly what they need.

0 commit comments

Comments
 (0)