diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index 6b9f7d1391e..df438d47eee 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -396,6 +396,38 @@ describe('defineCustomElement', () => { expect(e.value).toBe('hi') }) + // #12214 + test('Boolean prop with default true', async () => { + const E = defineCustomElement({ + props: { + foo: { + type: Boolean, + default: true, + }, + }, + render() { + return String(this.foo) + }, + }) + customElements.define('my-el-default-true', E) + container.innerHTML = `` + const e = container.childNodes[0] as HTMLElement & { foo: any }, + shadowRoot = e.shadowRoot as ShadowRoot + expect(shadowRoot.innerHTML).toBe('true') + e.foo = undefined + await nextTick() + expect(shadowRoot.innerHTML).toBe('true') + e.foo = false + await nextTick() + expect(shadowRoot.innerHTML).toBe('false') + e.foo = null + await nextTick() + expect(shadowRoot.innerHTML).toBe('null') + e.foo = '' + await nextTick() + expect(shadowRoot.innerHTML).toBe('true') + }) + test('support direct setup function syntax with extra options', () => { const E = defineCustomElement( props => { diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index 6ddaf897130..aeeaeec9b9f 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -505,6 +505,8 @@ export class VueElement } // reflect if (shouldReflect) { + const ob = this._ob + ob && ob.disconnect() if (val === true) { this.setAttribute(hyphenate(key), '') } else if (typeof val === 'string' || typeof val === 'number') { @@ -512,6 +514,7 @@ export class VueElement } else if (!val) { this.removeAttribute(hyphenate(key)) } + ob && ob.observe(this, { attributes: true }) } } }