Scoped style behavior with teleport & fragment
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
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
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.
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?
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
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.