vuejs-scoped-styles

What are scoped styles in Vue.js and how to use them

  • 2 min

Scoped styles are a way to encapsulate CSS styles within a specific component.

As applications grow, global styles can become difficult to maintain and can lead to conflicts between components.

This is where scoped styles come into play, a feature of Vue.js that allows you to encapsulate styles within a component.

Scoped styles are styles that are applied only to the component in which they are defined, avoiding conflicts with other components.

How to Use Scoped Styles in Vue.js

To use scoped styles in Vue.js, simply add the scoped attribute to the <style> tag in your component.

<template>
  <div class="container">
    <p class="text">This is styled text.</p>
  </div>
</template>

<style scoped>
.container {
  padding: 20px;
  border: 1px solid #ccc;
}

.text {
  color: blue;
  font-size: 18px;
}
</style>

In this example,

  • The styles defined in <style scoped> apply only to the elements within the component.

How Scoped Styles Work Internally

When we define styles with the scoped attribute in a component, Vue.js automatically makes a series of modifications to the elements when rendering it.

  1. Adds a unique attribute: Each element of the component is assigned a unique attribute, like data-v-123456.
  2. Modifies the CSS selectors: Vue.js modifies the CSS selectors to include the unique attribute.

For example, the following CSS:

.container {
  padding: 20px;
}

Will become:

.container[data-v-123456] {
  padding: 20px;
}

This ensures that the styles are only applied to the elements of the current component.

This happens transparently for us, without us having to worry about (almost) anything.

Propagating Styles to Child Components with Deep

By default, styles with scoped do not apply to child components. However, in some cases, we may want them to propagate.

For this, Vue.js provides the deep selector (:deep()).

<template>
  <div class="parent">
    <ChildComponent />
  </div>
</template>

<script setup>
import ChildComponent from './ChildComponent.vue';
</script>

<style scoped>
.parent :deep(.child-class) {
  color: red;
}
</style>

In this example, the style is applied to elements with the class child-class inside the ChildComponent, even though the styles are defined with scoped.

Applying Styles to Slot Elements with :slotted

Similarly, when working with slots, Vue.js does not propagate scoped styles to slots by default. To do this, it provides the :slotted() selector.

<template>
  <div class="wrapper">
    <slot></slot>
  </div>
</template>

<style scoped>
:slotted(p) {
  font-weight: bold;
  color: green;
}

/* You can also use classes or more complex combinations */
:slotted(.special) {
  background-color: #eee;
}
</style>

In this example:

  • The selector :slotted(p) will apply to all <p> elements that are inserted into the component’s slot.
  • The selector :slotted(.special) will apply to any element with the class special that is inserted into the slot.