Custom element property overrides are not working as expected due to prototype handling.
The issue involves custom element property overrides not being respected due to how properties are defined during mounting. The fix requires modifying property definition in the custom element API, but there are already competing PRs addressing this.
v3.5.18
https://stackblitz.com/edit/vitejs-vite-nhmrulst?file=src%2Fmain.js
I'm creating a custom datepicker control. Similar to the native <input type="datepicker"> control, I want to reject assignments to the value property that aren't valid dates.
An easy solution would be to subclass the custom element:
const baseCustomElement = defineCustomElement({
props: { myProp: Date },
setup(props) { ... },
});
class DerivedCustomElement extends baseCustomElement {
set myProp(newValue) { if (isValid(newValue)) { super.myProp = newValue; } }
}
However, this doesn't work:
customElements.define("my-elem", DerivedCustomElement);
const elem = document.createElement("my-elem");
document.body.append(elem);
elem.myProp = "invalid value";
console.log(elem.myProp); // returns "invalid value"
DerivedCustomElement.myProp's setter should be called, and should not pass the new value into the component.
The setter is never called, because it is overridden when the component is mounted. This is done in apiCustomElement:_resolveProps. The comment, "// defining getter/setters on prototype", makes me think this is a bug.
An alternative solution for my use case would be to enforce prop validation in apiCustomElement, and not call _setProp if validation fails. However, this would have wider effects and would probably need more analysis, an option to toggle it off, and so on.
My proposed fix is to define the properties on the prototype, for real. In addition to making them overridable, this would probably also result in a small speedup, as they wouldn't have to be defined every time an instance is created and mounted. I'd be happy to make a pull request f
Claim this issue to let others know you're working on it. You'll earn 10 points when you complete it!