-
Notifications
You must be signed in to change notification settings - Fork 375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider functional mixin pattern for form-associated custom elements #812
Comments
Hey, thanks for sharing this! My initial impression is that this is a good, opinionated pattern for frameworks and libraries to build on top of ElementInternals, but as a base primitive, ElementInternals is simpler and more flexible. For example, it allows you to create classes which don't have custom mixin-based inheritance hierarchies, instead deriving directly from HTMLElement like all the native form controls do. I'm also having a bit of trouble understanding the stated advantages of this pattern, on the level of primitives. In particular, statements like
don't seem like advantages to me over the current proposal's "If someone wants form support, they add
This doesn't work with JavaScript private, because the private fields you declare only belong to the But that said, again, I really think there's room for an opinionated framework to make writing FACEs easier with mixins, or codegen, or the like. For example, it could automatically provide public properties/methods for type/disabled/form/labels/name/willValidate/validity/validationMessage/checkValidity/reportValidity/setCustomValidity, which are kind of cookie-cutter re-exposures if you don't use a framework. I know @justinfagnani was also interested in exploring this space. Curious about your thoughts! |
I don't have a lot to add to what @domenic said. The fact that we can write useful mixins in userland is great, and seems like the basis for a good standalone library. I would emphasize that trying to automatically handle A mixin can override const setFormValue = Symbol(FormAssociated.'setFormValue');
export const FormAssociated = (base) => class FormAssociated extends base {
#internals;
#internalsRetreived = false;
constructor() {
super();
this.#internals = this.attachInternals();
// allow another attachInternals() call, from the leaf class, or a mixin
// that follows this pattern
this.#internalsRetreived = false;
}
attachInternals() {
if (this.#internalsRetreived) {
throw new InvalidStateError('ElementInternals already requested');
}
this.#internalsRetreived = true;
return this.#internals;
}
[setFormValue](value, state) {
this.#internals.setFormValue(value, state);
}
}
FormAssociated.setFormValue = setFormValue; import {FormAssociated} from 'form-associated';
class MyControl = FormAssociated(HTMLElement) {
#internals;
constructor() {
// maybe for AOM, pseudo-classes, etc.
this.#internals = this.attachInternals();
}
formResetCallback() {
this.value = '';
this[FormAssociated.setFormValue](this.value);
}
} |
I'm not sure I understand how this is a mixin. At least, given a hypothetical AriaDescribedByTargetMixin, how would my component use both that and FormAssociatedMixin? |
class MyControl extends AriaDescribedByTargetMixin(FormAssociatedMixin(HTMLElement)) {
} |
My original point has been heard, so closing this. |
Rather than incorporating support for forms into all custom elements, I was wondering whether it’s worth exploring a functional mixin pattern for defining form support. This would keep form features from affecting components that don’t need those features.
In this approach, form participation would be defined through a mixin function that can be applied a base class (either
HTMLElement
, or a class deriving from it) to return a new form-capable class. JavaScript pseudo-code for such a mixin would look like:Authors creating custom elements with forms in mind would then apply this
FormAssociatedMixin
to the base class they extend. The sample custom element from the Form Participation Explainer might look like:If someone wants form support, they extend
FormAssociatedMixin(HTMLElement)
; if they don’t intend their component to be used with forms, they extendHTMLElement
as they do now.Among other things, this could keep
ElementInternals
clean for components that don’t support forms. The form-related properties and methods currently planned forElementInternals
could become private properties and methods:And then invoked directly on
this
, rather than onElementInternals
:I make this suggestion only because the Elix project I lead has gotten so much mileage out of the extensive set of functional mixins; we’ve defined this way. After several years of creating components, I can say that it’s really nice to keep optional behavior out of base classes, and only bring them into play when needed. I think form participation is a good example of such optional behavior, so perhaps a mixin approach would work well for it.
The text was updated successfully, but these errors were encountered: