vue-loader: Scoped styles don't apply to v-html injections

Version

11.0.0

Reproduction link

https://github.com/foundryspatial-duncan/vue-loader-issue-demo/blob/master/src/App.vue

Steps to reproduce

  1. In a single-file Vue component (.vue file), add some scoped styles (with the scoped property on the style tag).
  2. Inject some HTML that matches your scoped style’s selector with v-html

What is expected?

The styles would affect the injected HTML

What is actually happening?

The styles do not affect the injected HTML


Looks like HTML injected with v-html aren’t given the “data-v-[hash]” property (like data-v-08ce5946). I think there’s a proposal somewhere to only add the data-v-[hash] to the component’s root element and then prefix all the styles to scope them. That would solve this issue as well.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 7
  • Comments: 20 (1 by maintainers)

Most upvoted comments

You can use the /deep/ selector to get your styles to be applied:

<div class="description" v-if="description" v-html="description"></div>

.description {
  /deep/ p {
    margin-bottom: 10px;
  }
}

I stumbled upon this today and oddly, nothing was working (unscoped css, global css).

I noticed that while this solution worked, the /deep/ selector was deprecated by some time ago and throws errors in IE: https://stackoverflow.com/questions/25609678/what-do-deep-and-shadow-mean-in-a-css-selector

I then found this: https://medium.com/@brockreece/scoped-styles-with-v-html-c0f6d2dc5d8e

Which recommends something along the lines of:

.description >>> p {
  margin-bottom: 10px;
}

Which works as well, without a deprecated selector.

edit: Then again, the vue docs say >>> is just an alias for /deep/, so I’m not sure anymore https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

Prefixing is simply different from what scoped CSS does. The HTML injected is raw and we are likely not going to change this. You can just give the container element a class and use nested selectors to style the raw HTML.

Try this 😃

<div class="content" v-html="content"></div>
.content ::v-deep {
  h2 {
    color: blue;
  }
  a {
    color: blue;
  }
}

/deep/ is not working in Vue@2.6.12 use ::v-deep instead. .right { ::v-deep * { ... } }

Not sure if I missed it, but would be great to put a mention in the Docs about this not working (might save some churn for other noobs like myself 😃 )

You can use the /deep/ selector to get your styles to be applied:

<div class="description" v-if="description" v-html="description"></div>

.description {
  /deep/ p {
    margin-bottom: 10px;
  }
}

wow! /deep/ works. learned something today 😃

How do I use /deep/ or >>> or ::v-deep in Vue.js?

To add styles to child components from the parent component…

In Vue 2:

  • The /deep/ syntax is deprecated
  • Use ::v-deep with Sass, use >>> without Sass
<style scoped>
    .parent-component {
        ::v-deep {
            .child-component {
                background-color: #000000;

                p {
                    color: #ffffff;
                }
            }
        }
    }
</style>

In Vue 3:

  • ::v-deep .child-class is deprecated in favor of :deep(.child-class)
  • The ::v- prefix is deprecated in favor of :
  • The >>> syntax is deprecated
  • The /deep/ syntax is deprecated
<style scoped>
    .parent-component {
        :deep {
            (.child-component) {
                background-color: #000000;

                p {
                    color: #ffffff;
                }
            }
        }
    }
</style>

Also in Vue 3 you can use 2 new selectors:

  • To register global styles even from a scoped component you can use the:global(.my-class) selector.
  • For access to <slot> element you can use :slotted(.child-class) selector.
<style scoped>
    .parent-component {
        :global {
            p {
                color: #000000;
            }

            (.my-class) {
                background-color: #000000;

                p {
                    color: #ffffff;
                }
            }
        }

        :slotted {
            (.slot-child-component) {
                background-color: #000000;

                p {
                    color: #ffffff;
                }
            }
        }
    }
</style>

Update!!! As of March 2022 the /deep/ and >>> deep selectors have been deprecated. Now you should use :deep()

.a :deep(p) {} to go deeper and target the p tag

/deep/ p

not working with with scss

In my case, with scss, it is working pretty fine:

    /deep/ &-icon {
      // See: https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors
      font-size: 30px;
    }

/deep/ p

not working with with scss

I am using <style lang="scss" module> and I am passing a raw html from my backend config. footer: 'some text \n'+ '<a href="#" :class="$style.tc">link</a>', In the original component: <div :class="$style.footer"> <p :class="$style['footer-text']" v-html="footer"></p> </div>


.footer-text{ /deep/ a{ color: #1665c0; text-decoration: none; } } The above style is applied to the link element and it works fine. But when I replace ‘a’ with ‘.tc’(class name) it does not work. .footer-text{ /deep/ .tc{ color: #1665c0; text-decoration: none; } } Also the alias for ‘/deep/’ ,i.e, ‘>>>’ does not work

Would it be a good idea to add this to the documentation?

You can use the /deep/ selector to get your styles to be applied:

<div class="description" v-if="description" v-html="description"></div>

.description {
  /deep/ p {
    margin-bottom: 10px;
  }
}

/deep/ works bro, tks so much