diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index df438d47eee..fd8608c916f 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -1131,6 +1131,92 @@ describe('defineCustomElement', () => { expect(target.innerHTML).toBe(`default`) app.unmount() }) + + test('toggle nested custom element with shadowRoot: false', async () => { + customElements.define( + 'my-el-child-shadow-false', + defineCustomElement( + { + render(ctx: any) { + return h('div', null, [renderSlot(ctx.$slots, 'default')]) + }, + }, + { shadowRoot: false }, + ), + ) + const ChildWrapper = { + render() { + return h('my-el-child-shadow-false', null, 'child') + }, + } + + customElements.define( + 'my-el-parent-shadow-false', + defineCustomElement( + { + props: { + isShown: { type: Boolean, required: true }, + }, + render(ctx: any, _: any, $props: any) { + return $props.isShown + ? h('div', { key: 0 }, [renderSlot(ctx.$slots, 'default')]) + : null + }, + }, + { shadowRoot: false }, + ), + ) + const ParentWrapper = { + props: { + isShown: { type: Boolean, required: true }, + }, + render(ctx: any, _: any, $props: any) { + return h('my-el-parent-shadow-false', { isShown: $props.isShown }, [ + renderSlot(ctx.$slots, 'default'), + ]) + }, + } + + const isShown = ref(true) + const App = { + render() { + return h(ParentWrapper, { isShown: isShown.value } as any, { + default: () => [h(ChildWrapper)], + }) + }, + } + const container = document.createElement('div') + document.body.appendChild(container) + const app = createApp(App) + app.mount(container) + expect(container.innerHTML).toBe( + `` + + `
` + + `` + + `
child
` + + `
` + + `
` + + `
`, + ) + + isShown.value = false + await nextTick() + expect(container.innerHTML).toBe( + ``, + ) + + isShown.value = true + await nextTick() + expect(container.innerHTML).toBe( + `` + + `
` + + `` + + `
child
` + + `
` + + `
` + + `
`, + ) + }) }) describe('helpers', () => { diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index aeeaeec9b9f..e65eef77204 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -280,7 +280,8 @@ export class VueElement // avoid resolving component if it's not connected if (!this.isConnected) return - if (!this.shadowRoot) { + // avoid re-parsing slots if already resolved + if (!this.shadowRoot && !this._resolved) { this._parseSlots() } this._connected = true @@ -298,8 +299,7 @@ export class VueElement if (!this._instance) { if (this._resolved) { - this._setParent() - this._update() + this._mount(this._def) } else { if (parent && parent._pendingResolve) { this._pendingResolve = parent._pendingResolve.then(() => {