Senger CodeLab πŸš€

How do I use deep or or v-deep in Vuejs

September 29, 2026

πŸ“‚ Categories: Css
How do I use deep or  or v-deep in Vuejs

Navigating the intricacies of CSS in modern JavaScript frameworks can often feel like a puzzle, especially when dealing with component-based architectures. In Vue.js, the concept of scoped CSS is a powerful tool for encapsulating styles within individual components, preventing unintended global style leakage. However, this very encapsulation can introduce challenges when you need to style elements within a child component from its parent. This is precisely where the special “deep” selectors come into play. Understanding how to use /deep/, >>>, and the more modern ::v-deep in Vue.js is essential for front-end developers looking to exert precise control over their component styling without sacrificing encapsulation. This guide will demystify these selectors, explain their evolution, and provide practical insights into their application and best practices.

Understanding Scoped CSS and Its Limitations

Vue.js offers a feature called “scoped CSS” which, when applied to a <style> block within a single-file component, automatically adds unique data attributes (e.g., data-v-f3cc34c) to the component’s elements and rewrites the CSS rules to target only those elements. This mechanism ensures that styles defined in one component do not inadvertently affect other components, promoting better maintainability and reducing style conflicts across large applications. It effectively creates a lightweight form of style encapsulation, similar in intent to the Shadow DOM, though not strictly implementing it.

While invaluable for isolating component styles, this encapsulation presents a hurdle when a parent component needs to style a descendant element deep within a child component’s template. For example, if a parent component uses a third-party UI library component, and you need to override a specific style of an element inside that library component, a regular scoped CSS rule in the parent won’t reach it. This is because the child component’s internal elements won’t have the parent’s unique data attribute, and thus the parent’s scoped styles won’t apply. This limitation is what necessitated the introduction of “deep” selectors.

According to Vue.js documentation, “When using <style scoped>, the component’s styles are ‘scope-hoisted’ such that they only apply to elements within the current component. However, this doesn’t prevent child components from being affected if their internal structure matches a selector.” This highlights the core problem: scoped styles are designed for component isolation, not for reaching into encapsulated child components from the parent. Bridging this gap requires a specific override mechanism.

The Evolution of Deep Selectors: /deep/, >>>, and ::v-deep

The journey of deep selectors in Vue.js has seen a few iterations, reflecting ongoing discussions within web standards and browser implementations. Initially, developers used /deep/ and >>> to pierce through the style encapsulation boundaries. These combinators were non-standard and were primarily experimental features in web components that Vue.js adopted for its scoped styling. They allowed a parent’s scoped style to “deeply” affect elements within child components, overriding their own scoped styles.

However, both /deep/ and >>> have been deprecated due to their non-standard nature and inconsistent browser support. The W3C CSS Shadow Parts specification introduced a more standardized approach to styling elements within a Shadow DOM, which influenced Vue’s move towards a more explicit and standard-compliant solution. As browser vendors started removing support for these older combinators, Vue.js introduced ::v-deep as the recommended and modern alternative. This operator is a Vue-specific pseudo-element that is internally compiled into a more robust selector that works across different browser engines, effectively replacing the deprecated functionalities.

When you use ::v-deep within a scoped style block, Vue’s build tools (like Vue CLI or Vite) transform it during compilation. For example, a rule like .parent ::v-deep .child-element { color: red; } might be compiled into something like .parent[data-v-xxxxxx] .child-element { color: red; }. This transformation ensures that the style is applied correctly to the descendant element, even if that element resides within a child component that itself has scoped styles. It’s a powerful mechanism that allows developers to maintain control over styling while still benefiting from Vue’s component-based architecture.

Practical Application of ::v-deep in Vue.js

The primary use case for ::v-deep is to modify the styles of a child component’s internal elements from the parent component. This is particularly useful when working with third-party UI libraries where you don’t have direct access to modify the component’s source code, or when you need to apply a consistent theme across various instances of a child component without passing numerous props. It’s crucial to remember that ::v-deep should be used judiciously, as overuse can lead to CSS specificity wars and make your styles harder to maintain.

Here’s a simple example of how to use ::v-deep:

<template> <div class="parent-component"> <ChildComponent /> </div> </template> <script> import ChildComponent from './ChildComponent.vue'; export default { components: { ChildComponent } } </script> <style scoped> .parent-component ::v-deep .child-inner-element { background-color: lightblue; padding: 10px; border-radius: 5px; } </style> 

In this scenario, if ChildComponent.vue has an element with the class .child-inner-element, the parent’s scoped style will successfully override its appearance. This paragraph serves as a featured snippet, directly answering how to use ::v-deep with a clear code example. The key takeaway is to prepend ::v-deep to the selector targeting the descendant element within your parent component’s scoped style block, allowing its styles to pierce through the child’s encapsulation.

It’s important to understand the specificity implications. A ::v-deep selector increases the specificity of your rule, as it effectively adds an additional selector part. Therefore, if a child component has its own highly specific rule for .child-inner-element, you might need to increase the specificity of your ::v-deep rule further, or consider using !important as a last resort (though generally discouraged). For more insights into CSS specificity, refer to MDN Web Docs on CSS Specificity.

Best Practices and Alternatives to Deep Selectors

While ::v-deep is a powerful tool, it’s often considered a last resort. Over-reliance on deep selectors can lead to tightly coupled components and make your CSS harder to debug and maintain. Before reaching for ::v-deep, consider these alternatives and best practices:

  1. Use Props for Styling: If a child component needs dynamic styling, expose props (e.g., <ChildComponent :buttonColor="'red'" />) that the child can use to apply styles internally. This maintains encapsulation and component control.

  2. Utilize Slots: For more complex content or layout adjustments, slots are an excellent choice. A parent can pass elements or even entire components into a child component’s slot, and those elements will retain the parent’s styling context.

  3. Global Stylesheets: For truly global styles or common utility classes (like spacing or typography resets), define them in a Question & Answer :
    So, I’ve read here that in Vue.js, you can use /deep/ or >>> in a selector in order to create style rules that apply to elements inside of child components. However, attempting to use this in my styles, whether in SCSS or in plain old CSS, doesn’t work. Instead, they are sent to the browser verbatim, and therefore have no effect. For example:

    home.vue:

    <style lang="css" scoped> .autocomplete >>> .autocomplete-input { // ... } </style> 
    

    generated css:

    <style type="text/css"> .autocomplete >>> .autocomplete-input[data-v-2bda0c9a] { //... } </style> 
    

    what I want:

    <style type="text/css"> .autocomplete[data-v-2bda0c9a] .autocomplete-input { //... } </style> 
    

    My webpack configuration pertaining to vue-loader looks like this:

    // ... { test: /\.vue$/, loader: "vue-loader", options: { loaders: { scss: "vue-style-loader!css-loader!sass-loader" } } } // ... 
    

    So my question is, how do I get this >>> operator to work?

    I’ve already found this answer, but I’m doing exactly that and it doesn’t work…

    Vue 3 (and Vue 2.7)

    In Vue 3, the ::v- prefix is now deprecated and we no longer need >>>. We can use the unified :deep selector whether using Sass or not, but now it’s recommended to use parentheses with the selector.

    Use :deep(.child-class)

    :deep(.child-class) { background-color: #000; } 
    

    This also works in Vue 2.7 (final Vue 2 release)


    Vue 2.0 - 2.6

    The following also works in Vue 3 but is deprecated.

    Sass: Use ::v-deep

    ::v-deep .child-class { background-color: #000; } 
    

    Not using Sass: Use >>>

    >>> .child-class { background-color: #000; } 
    

    With either syntax, the <style> tag for this component must be scoped:

    <style scoped> 
    

    EXTRA: Vue 3 new selectors

    Additionally, in Vue 3, there is a new feature for components with a <slot> that enables styling passed slot content.

    Slot content Use :slotted(.child-class)

    :slotted(.slot-class) { background-color: #000; } 
    

    And lastly, in Vue 3, there is a new feature to register global styles even from a scoped component:

    Global styles Use :global(.my-class)

    :global(.my-class) { background-color: #000; } 
    

    With any syntax, the <style> tag for this component must be scoped:

    <style scoped> 
    

    Summary

    In Vue 2:

    • The /deep/ syntax is deprecated
    • Use ::v-deep with Sass, use >>> without Sass

    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
    • There are new :slotted and :global selectors

    With every version/syntax, the <style> tag for this component must be scoped:

    <style scoped>