Skip to content

Commit 8ff918a

Browse files
OlTreninclaude
andcommitted
fix(runtime-dom): allow custom element prop overrides via prototype (#13706)
Define custom element properties on prototype instead of instance to allow subclasses to override property setters for validation and custom behavior. Fixes #13706 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent c875019 commit 8ff918a

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

packages/runtime-dom/__tests__/customElement.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,47 @@ describe('defineCustomElement', () => {
14011401
})
14021402
})
14031403

1404+
test('subclasses can override property setters', async () => {
1405+
const E = defineCustomElement({
1406+
props: {
1407+
value: String,
1408+
},
1409+
render() {
1410+
return h('div', this.value)
1411+
},
1412+
})
1413+
1414+
class SubclassedElement extends E {
1415+
set value(val: string) {
1416+
if (val && val !== 'valid-date' && val.includes('invalid')) {
1417+
return
1418+
}
1419+
super.value = val
1420+
}
1421+
1422+
get value(): string {
1423+
return super.value || ''
1424+
}
1425+
}
1426+
1427+
customElements.define('my-subclassed-element', SubclassedElement)
1428+
1429+
const e = new SubclassedElement()
1430+
container.appendChild(e)
1431+
1432+
e.value = 'valid-date'
1433+
await nextTick()
1434+
expect(e.shadowRoot!.innerHTML).toBe('<div>valid-date</div>')
1435+
1436+
e.value = 'invalid-date'
1437+
await nextTick()
1438+
expect(e.shadowRoot!.innerHTML).toBe('<div>valid-date</div>') // Should remain unchanged
1439+
1440+
e.value = 'another-valid'
1441+
await nextTick()
1442+
expect(e.shadowRoot!.innerHTML).toBe('<div>another-valid</div>')
1443+
})
1444+
14041445
describe('expose', () => {
14051446
test('expose w/ options api', async () => {
14061447
const E = defineCustomElement({

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -456,14 +456,16 @@ export class VueElement
456456

457457
// defining getter/setters on prototype
458458
for (const key of declaredPropKeys.map(camelize)) {
459-
Object.defineProperty(this, key, {
460-
get() {
461-
return this._getProp(key)
462-
},
463-
set(val) {
464-
this._setProp(key, val, true, true)
465-
},
466-
})
459+
if (!Object.prototype.hasOwnProperty.call(this.constructor.prototype, key)) {
460+
Object.defineProperty(this.constructor.prototype, key, {
461+
get() {
462+
return this._getProp(key)
463+
},
464+
set(val) {
465+
this._setProp(key, val, true, true)
466+
},
467+
})
468+
}
467469
}
468470
}
469471

0 commit comments

Comments
 (0)