I am trying to migrate some Vue.js Single File Components from ::v-deep syntax to :deep(), as described here. However, I am not sure how to make it work with nested SCSS rules with &__*. Rules without &__* work just fine.
The SCSS compiler we use is dart-sass.
For example, having this original snippet:
::v-deep .wrapper {
display: flex;
&__element {
display: block
}
}
Correctly compiles the code to
[data-v-S0m3Ha5h] .wrapper__element {
display: block;
}
And throws a warning: [@vue/compiler-sfc] ::v-deep usage as a combinator has been deprecated. Use :deep(<inner-selector>) instead.
:deep() in top-level ruleI have tried converting it to :deep() like this:
:deep(.wrapper) {
display: flex;
&__element {
display: block
}
}
which results in a compiler error, because :deep(wrapper)__element is not a valid selector.
:deep() in the nested ruleSo I moved the :deep to the nested rule:
.wrapper {
display: flex;
:deep(&__element) {
display: block
}
}
which compiles without errors, but produces botched css:
.wrapper[data-v-S0m3Ha5h] &__element {/* ... */}
How can I use nested &__* rules with :deep()?
Sass apparently doesn't allow the selector argument list of :deep(or of any other pseudo-class) to be nested because of the reason you mentioned, but there are a couple workarounds.
Split up the styles so that :deep's selector list is not nested:
<!-- MyParent.vue -->
<style scoped lang="scss">
:deep(.wrapper) {
display: flex;
}
:deep(.wrapper__element) {
display: block;
}
</style>
Break up the BEM class names (from wrapper__element to __element) so that parent selectors are not necessary:
<!-- MyComponent.vue -->
<template>
<div class="wrapper">
<div class="__element">...</div>
</div>
</template>
or augment wrapper__element with an additional __element class (if you can ignore the repetition):
<!-- MyComponent.vue -->
<template>
<div class="wrapper">
<div class="wrapper__element __element">...</div>
</div>
</template>
For some reason, this scenario requires :deep to based on a selector (e.g., root in the example below):
<!-- MyParent.vue -->
<template>
<div class="root">
<MyComponent />
</div>
</template>
<style scoped lang="scss">
.root:deep(.wrapper) {
display: flex;
.__element {
display: block;
}
}
</style>
<!-- MyComponent.vue -->
<template>
<div class="wrapper">
<h1>.wrapper</h1>
<!-- Add __element class here 👇 (and optionally remove wrapper__element) -->
<div class="wrapper__element __element">
<h1>.wrapper__element</h1>
</div>
</div>
</template>