vuejs / core

đź–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.78k stars 8.35k forks source link

Teleport + CSS v-bind does not work with shadow target #12287

Open Mefinst opened 3 weeks ago

Mefinst commented 3 weeks ago

Vue version

3.4.15, 3.5.12

Link to minimal reproduction

https://stackblitz.com/edit/vitejs-vite-qg9sjb?file=src%2Fcomponents%2FHelloWorld.vue

Steps to reproduce

  1. Mount vue app inside shadow root (manually or using custom elements feature of vue).
  2. Setup element with a class and put it to teleport (teleport target should be outside current component tree, but inside shadow tree)
  3. Set some css properties of the class to v-bind values in SFC of component containing teleport

In the linked example I set an element with class v-bind-fail to have red background using v-bind. But it is white.

What is expected?

v-bind styles are applied to teleported dom element.

What is actually happening?

v-bind styles are not applied to teleported dom element.

System Info

No response

Any additional comments?

v-bind is implemented using var(--some-hash) custom properties. Values for those provided by inline style attributes. When some part of a component is inside teleport tag those style attributes duplicated there. At least normally so. When teleport target is inside shadow dom styles aren't duplicated.

From my perspective v-bind implementation expects teleport to be used with selectors only, but it can be used with HTMLElement variable which can point to shadow tree element. It seems v-bind implementation uses something similar to document.querySelector to apply variables to teleported parts of the tree. And it fails to locate elements in the shadow tree.

KamilOcean commented 3 weeks ago

Hi, @Mefinst !

May be I get something wrong, but I think the problem is that you are trying to apply CSS classes outside of incapsulated shadowDOM to that shadowDOM element. But as I know it doesn't work by the nature of native elements' incapsulation concept.

There are special techniques for this case. I've changed a little bit your example in order to make it work. I've used ::part(inside-teleport):

template:

  <teleport :to="teleTarget">
    <div part="inside-teleport" class="v-bind-fail">Failure</div>
  </teleport>