:deep() syntax with nested scss rules
Asked Answered
M

1

6

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.

Example

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 rule

I 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 rule

So 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 {/* ... */}

Question

How can I use nested &__* rules with :deep()?

Maritsa answered 17/8, 2022 at 7:52 Comment(0)
R
3

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.

Workaround 1: Split up the Sass styles

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>

demo 1

Workaround 2: Split up the class names

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>

demo 2

Rhetorical answered 18/8, 2022 at 0:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.