]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(custom-element): properly locate parent when slotted in shadow dom (#12480)
authorlejunyang <1329327499@qq.com>
Mon, 9 Mar 2026 06:13:22 +0000 (14:13 +0800)
committerGitHub <noreply@github.com>
Mon, 9 Mar 2026 06:13:22 +0000 (14:13 +0800)
close #12479

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

index 1225326abc50519d7b9a30f15d40a83ad143f151..8aa02dbe80c1fe1b9d96e3b895078dc8cbf2f3c9 100644 (file)
@@ -995,6 +995,31 @@ describe('defineCustomElement', () => {
       )
     })
 
+    test('should resolve correct parent when element is slotted in shadow DOM', async () => {
+      const GrandParent = defineCustomElement({
+        provide: {
+          foo: ref('GrandParent'),
+        },
+        render() {
+          return h('my-parent-in-shadow', h('slot'))
+        },
+      })
+      const Parent = defineCustomElement({
+        provide: {
+          foo: ref('Parent'),
+        },
+        render() {
+          return h('slot')
+        },
+      })
+      customElements.define('my-grand-parent', GrandParent)
+      customElements.define('my-parent-in-shadow', Parent)
+      container.innerHTML = `<my-grand-parent><my-consumer></my-consumer></my-grand-parent>`
+      const grandParent = container.childNodes[0] as VueElement,
+        consumer = grandParent.firstElementChild as VueElement
+      expect(consumer.shadowRoot!.textContent).toBe('Parent')
+    })
+
     // #13212
     test('inherited from app context within nested elements', async () => {
       const outerValues: (string | undefined)[] = []
index 9d18e7b22108974ea52989c501c0026db0d99c11..9c0e115163c35a2d022e32c5d0c5bc3643c633fd 100644 (file)
@@ -291,7 +291,12 @@ export class VueElement
     // locate nearest Vue custom element parent for provide/inject
     let parent: Node | null = this
     while (
-      (parent = parent && (parent.parentNode || (parent as ShadowRoot).host))
+      (parent =
+        parent &&
+        // #12479 should check assignedSlot first to get correct parent
+        ((parent as Element).assignedSlot ||
+          parent.parentNode ||
+          (parent as ShadowRoot).host))
     ) {
       if (parent instanceof VueElement) {
         this._parent = parent