Subscribe on changes!

Scoped style behavior with teleport & fragment

avatar
Nov 25th 2020

Version

3.0.2

Reproduction link

https://codesandbox.io/s/aged-butterfly-4ryvl?file=/src/components/CompB.vue

Steps to reproduce

follow the link

What is expected?

as my expected, at least the binded element should have proper data-xxx attr to make scoped style works well

What is actually happening?

not applied in any circumstance

avatar
Nov 25th 2020

Note $attrs doesn't contain the data-v-.... It would be inconvenient:

Parent component:

<template>
  <input >
  <CustomInput />
</template>

<style scoped>
input {
 color: red;
}

CustomInput.vue:

<template>
  <div>
    <label>...</label>
    <input v-bind="$attrs">
  <div>
</template>

The custom input will accidentally inherit the color: red.

We could however maybe apply the data-v to all root elements in a fragment

avatar
Nov 26th 2020

Not only fragment-rooted component has no data-v, but also teleport-rooted component doesn't.

https://codesandbox.io/s/laughing-gagarin-4mlln?file=/src/components/CompB.vue

Since Teleport & Fragment can be nested for many levels. I think there should be a traversal to make sure the real outer-most html element is applied with data-v.

Nor we may need a mechanism to let user specify which part should be applied with scoped style from parent.


For example I have a component wrapped with HOC. Hoc1 and Hoc2 may be composed with Fragment & Teleport.

<!-- Comp.vue -->
<hoc-1>
  <hoc-2>
    <div class="x" />
  </hoc-2>
<hoc-1>

Suppose it will be rendered as just a <div class="x" />. It's expected that the outer scoped style is applied to the component.

avatar
Dec 17th 2020

I'm torn about what to do here.

In Vue 2, all components had root nodes, and we always applied the data-v property to child components' root element.

That actually was a caveat, as styles from the parent could accidentally bleed into the child if the child root contained a class of the same name (unintentionally), but at the same time, it gave authors an escape hatch to style the root of a child.

The behavior in Vue 3 now, is emulating what happened in Vue 2 for root nodes while skipping the behavior for fragments, which is in line with attribute inheritance in general, were we skip inheritance for fragments. As we have now reached a stable 3.0 release for a while, that can't be reversed without a breaking change, technically.

Could we find workarounds with :slotted() or :-deep() pseudoselectors?

avatar
Dec 10th 2021

This still not have been fixed yet ? Just run into this problem today. Spent a good 30m to understand why. I think the very least thing we can do is issue this problem in the doc about fragment. Because it is expected that everything have bound to an element, it should behave like the root of the child component

avatar
Dec 20th 2021

I would add that Vue does seem to add the data attribute to fragments on SSR, but not on client-side, as can be seen in this CodeSandbox - see linked issue.

avatar
May 9th 2022

maybe we can use getCurrentInstance().vnode.scopeId ?

avatar
Feb 6th 2023

Is this still relevant?

avatar
Nov 3rd 2023

@yyx990803 Sorry for the ping but would it be okay to use the internal API for this use case? getCurrentInstance()?.vnode.scopeId