Subscribe on changes!

`:deep` selector doesn't work properly with SASS nested parent selector

avatar
Sep 5th 2022

Vue version

v3.2.38

Link to minimal reproduction

https://codesandbox.io/s/sad-alex-uj6q2u?file=/src/components/HelloWorld.vue

Steps to reproduce

  • Write a computed property that returns an HTML element with a BEM-like class name
  • Output this property into a v-html in your component
  • Write the style for that class in SASS nested parent selector notation:
.element {
    &__block {
        color: #aa8855;
    }
}
  • In order to make it work as a deep dynamic v-html element, wrap the style in the :deep selector:
.element {
    :deep(&__block) {
        color: #aa8855;
    }
}
  • It does not work as expected

What is expected?

The style is applied correctly to the deep dynamic element

What is actually happening?

The style is not applied. This is because the :deep selector takes precedence to the SASS compilation phase, so the final CSS output to the browser is like

.element[data-v-ff5e6236] &__block { ... }

instead of

.element__block { ... }

System Info

System:
    OS: macOS 12.5.1
    CPU: (8) arm64 Apple M1
    Memory: 82.27 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.16.0 - ~/.nvm/versions/node/v16.16.0/bin/node
    Yarn: 1.22.19 - ~/git_tree/experimentation-platform/client/node_modules/.bin/yarn
    npm: 8.11.0 - ~/.nvm/versions/node/v16.16.0/bin/npm
  Browsers:
    Firefox: 103.0.2
    Safari: 15.6.1
  npmPackages:
    vue: ^3.2.38 => 3.2.38

Any additional comments?

No response

avatar
Sep 28th 2022

After a round of searching, there is really no good solution, unless you use less

avatar
May 10th 2023

Yes, this is a problem since third party components have callback functions that allow users to add custom CSS classes into their components but the problem is that the inserted classes lack scoping therefore they never get "selected" by the scoped CSS when using SCSS/SASS and the :deep selector in a nested class. This used to work with the previous ::v-deep selector.

avatar
May 10th 2023

I found a workaround but it involves using an additional class as an anchor for the :deep selector.

Using the above example from @arrudaje:

.element {
    &__block {
        color: #aa8855;
    }
}

You can add a dummy class (eg .parent):

:deep(.parent) {
    .element {
        &__block {
            color: #aa8855;
        }
    }
}

This will produce the following CSS output

.parent .element__block {
    color: ##aa8855;
}

Obviously, the drawback of this approach is that it introduces the need for an additional class which increases the size of the CSS generated as well as increasing the specificity of the CSS rule.

To use these classes you also need to use a new parent element or use an existing parent element and add the .parent class to it.