vue-loader
vue-loader copied to clipboard
When using scoped CSS, element in slot within transition element doesn't apply child scope
Version
11.0.0
Reproduction link
https://github.com/RuneInBoots/vue-issue
Steps to reproduce
We tried to use scoped CSS in our components. In our application we also make use of slots.
We came across the problem that the elements in the slots were only following the parent scope.
We know this because we inspected the element and saw only one data-v-[id]
, and because our styles weren't applied =]
After searching we found out that our issue lied with the <transition>
around our child component.
// childComponent.vue
<template lang="html">
<!-- <transition> -->
<section>
<h1>Child component</h1>
<h2>text inside child</h2>
<p>child sets background to gold</p>
<h2>text from parent with slot</h2>
<slot name="foobar"></slot>
</section>
<!-- </transition> -->
</template>
<style lang="css" scoped>
p {background-color: gold;}
</style>
// parentComponent.vue
<template lang="html">
<section>
<h1>parent component</h1>
<h2>text inside parent</h2>
<p>parent sets color to crimson</p>
<child-component>
<p slot="foobar"> text from inside parent trough slot</p>
</child-component>
</section>
</section>
</template>
<script>
import childComponent from 'components/childComponent.vue';
export default {
components: {childComponent}
}
</script>
<style lang="css" scoped>
p {color: crimson;}
</style>
What is expected?
the text "text from inside parent trough slot" should have the color crimson and background-color gold. It should follow both the parent and the child scope.
What is actually happening?
the text only get the color crimson. it doesn't follow the CSS of the child scope.


I have a similar issue
@RuneInBoots is absolutely correct that this is how slotted content should behave with scoped CSS. I've also run into this with scoped components and breaks the fundamental way CSS is supposed to work.
The "Cascading" aspect of Cascading Style Sheets dictates that styling should apply to the child of the parent element. When data/elements are slotted into the component that data/elements then become a child of the component itself. Having scoped styling should still respect the "law" of CSS in this regard.
Seemingly, the way around this now seems to be unscoped styles in the component. This then breaks with the idea of componentization. I want the styling in my component to ONLY apply to that component, otherwise I might as well just use global stylesheets (one of the things that the concept of components is supposed to "solve")
All this said, I think this is a pretty big issue and would like to see it resolved.
I might have a related issue, although i am not quite sure and can't reliably reproduce it.
In my case when i have a situation like
<template lang="html">
<wrapper-component>
<!-- ... -->
<div v-if="bar" slot="header" class="foo">
<span class="bar">{{ bar }}</span>
</div>
<!-- ... -->
</wrapper-component>
</template>
And assuming scope data attributes called data-1
for the wrapper-component
and data-2
for the component in question:
With scoped styling for .foo
, if bar
is false
at initial component render, .foo
does not get the correct scope attribute added when it enters the DOM later, it only gets data-1
.
With an added template tag as a workaround like this:
<template lang="html">
<wrapper-component>
<!-- ... -->
<div slot="header" class="foo">
<template v-if="bar">
<span class="bar">{{ bar }}</span>
</template>
</div>
<!-- ... -->
</wrapper-component>
</template>
It works just fine since .foo
is in the DOM from the beginning and correctly has data-1 data-2
.
Unfortunately i can't seem to reproduce it properly.
- In synthetic tests on webpackbin
.foo
and all of its children only ever havedata-2
. - In synthetic tests in our application
.foo
and all of its children all havedata-1 data-2
. - As mentioned before, in the practical case where the issue arises,
.foo
hasdata-1
while all of its children havedata-1 data-2
. If thev-if
condition istrue
from the start,.foo
also hasdata-1 data-2
.
+1 for similar structure of @senritsu's example. I'm using v-if on default slot. Currently using the template workaround and work, thanks @senritsu!
vue-loader version: 12.2.2 vue version: 2.4.4
Just ran into this issue myself. Currently using the /deep/
scss selector to get around it. If there's a better way to go about this, I'm all ears. :D
hehehe yw @mobilehobo
Hi guys, I'm from the future 😄 and I have the same issue, but in my case the v-if is on the slot itself within the wrapper-component. Weird thing is that it was working fine for quite some time until now and I haven't even touched a thing related to it (I confirmed it additionally), it just happened after some merges. Another weird thing is that it only happens on initial render, if I go and just re-save the wrapper component to trigger hot-reload, the scope attribute of the parent component is set correctly ¯_(ツ)_/¯ The only way I found to make it work is with use of /deep/ but it doesn't feel right.
Guys, we're using $vm0.$options._scopeId in context this, for overwrite selectors weight in child slot scope.
Before:
After:
I believe I've hit this same issue today. The scoped styles in the parent's slot stopped working when I removed an unrelated component from the child template. I can't make sense out of it. I did have a v-if
in the child's slot. I moved that v-if
to a new wrapper div around the child's slot, and it seems to work. This behaviour was very unexpected.