7 Quick Tips about Vue Styles You (Might) Didn’t Know
Single file components consist of three distinct entities: template, script and styles. All of them are important but the latter is often…
7 Quick Tips about Vue Styles You (Might) Didn’t Know

Single file components consist of three distinct entities: template, script and styles. All of them are important but the latter is often being neglected even though it can become complex and often cause frustration and bugs. A better understanding can improve code reviews and decrease debugging time.
Here are 7 tips to help you with that:
- Styling Scoped And Slotted Content
- Scoped Selector Performance
- Global Styles
- Javascript Variables in Styles
- CSS Modules
- Variables in CSS Vs SCSS
- SCSS include Vs extend
1. Styling Scoped And Slotted Content
Scoping the styles to affect only the current component is a great tactic to prevent component coupling and unexpected side effects.
It is achieved by adding the scoped attribute to transform the following:
<template>
<div class="title">Hello world!</div>
</template>
<style scoped>
.title {
font-size: 24px;
}
</style>
To:
<template>
<div class="title" data-v-7ba5bd90>Hello world!</div>
</template>
<style scoped>
.title[data-v-7ba5bd90] {
font-size: 24px;
}
</style>
[Try it](https://play.vuejs.org/#eNp9kcFOwzAQRH/F+FxSiXIKoRKgSsABEHD0JUq2wcWxLe8mDVT5d9aOWnqoerNn5lmz65288z7rO5C5LAhab0qCpbJCFLXuRWVKxFslSZMBJZePYIwTWxdMfVHMOcHRYn7E8RXpx4DAynmoWckSK3bxzbWzdIn6F3Jxde2HG2XHyCciwXImiUm71k22QWe5VQKVrFzrtYHw6kk7i0rm05PRK7nU9jlpFDqY7fXqC6rvE/oGh6gp+RYAIfQ82cGjMjRAk736eIGBzwezdXUX93DGfAd0posdp9h9Z2uufZRLbZ9a7wJp23ziaiCwuB8qFo3JMeWV5K95ODP6f91Ftkgc71SOfyznnDs=)
If you want a style to affect the child components you can use the deep selector.
<style scoped>
.a :deep(.b) {
/\* ... \*/
}
</style>
Which compiles to:
.a[data-v-7ba5bd90] .b {
/\* ... \*/
}
And the same goes for content inside a slot using the slotted selector.
<style scoped>
:slotted(div) {
color: red;
}
</style>
2. Scoped Selector Performance
Scoped styles do not eliminate the need for classes. Due to the way [CSS selectors work](https://blogs.windows.com/msedgedev/2023/01/17/the-truth-about-css-selector-performance/), p { color: red } will be many times slower when scoped. If you [use a class instead](https://v2.vuejs.org/v2/style-guide/#Element-selectors-with-scoped-use-with-caution) that performance hit is negligible.
<!-- DO -->
<template>
<h1 class="title">Hello world!</h1>
</template>
<style scoped>
.title {
font-size: 24px;
}
</style>
<!-- DONT -->
<template>
<h1>Hello world!</h1>
</template>
<style scoped>
h1 {
font-size: 24px;
}
</style>
3. Global Style
A style that affects the whole application is probably not a good idea. In case you want to do it anyway you can either mix a scoped with an unscoped style or use the :global pseudoselector
<style scoped>
:global(.red) {
color: red;
}
</style>
4. Javascript Variables in Styles
Since Vue version 3.2 it is possible to use v-bind inside the style tag. This can lead to some interesting use cases like implementing a color picker with a few lines of code.
<template>
<h1 class="text">Hello World!</h1>
<input type="color" v-model="color" />
</template>
<script setup>
import { ref } from "vue";
const color = ref("");
</script>
<style>
.text {
color: v-bind(color);
}
</style>
A more advanced use case would be making the icon sizes of [a reusable app icon component](/integrating-an-icon-library-to-a-vue-application-b342fee12fae) dynamic.
<template>
<p>
<input type="radio" v-model="size" :value="sizes.s" />S
<input type="radio" v-model="size" :value="sizes.m" />M
<input type="radio" v-model="size" :value="sizes.l" />L
<input type="radio" v-model="size" :value="sizes.xl" />XL
</p>
<div class="icon" />
</template>
<script setup lang="ts">
import { ref } from "vue";
enum sizes {
s = 8,
m = 16,
l = 32,
xl = 64,
}
const size = ref(sizes.xl);
</script>
<style>
.icon {
width: v-bind(size + "px");
height: v-bind(size + "px");
background: #cecece;
}
</style>
[Try it](https://play.vuejs.org/#eNqlUk1v1DAQ/Ssjc1gq2ix0UYVCWglQDyC+RDlw8MVNZrNuHdvyR5qy2v/OjFNKD7SXVQ4Zz7x5fvM8W/HO+2rMKGrRJBy8UQnPpAVofPlRoK3PCdKtx1Mpguq0kwLGo8F1aCgT9W+kRD0qkxnB51hFKc4u9iEYiODLPgSGCD7vQzAxw69C0SxnN5pOj9AaFSOhdOssdS2p0iwfeEfH2AbtE0RM2YNRtid4Ykuk1YN3IcEWAq5hB+vgBljQAyy4EW0eoNwOW74vwim8OeRooOjVSQkNhavjEk4cn7yWdsfdpCfSpdROWaJ//neOA1Y4a7rTl24NS614hvmqG92lTU2mXGrblU54AQs/LQ7ecnmDut+kGh4BMORStdd9cNl2NTxrkb/SmoKyUSftbA3KGHhZHUdAFfHI5VSkk7giSBySS6RorfvqKjpLS1m0SdG6wWuD4ZtnHnKynlVzjTjdzaeSSyFjMab0bLC9/k/+Kk6ck+J7wIhhpKe/ryUVekxz+fziK04U3xdpXbIh9BPFHxidyaxxhr0nN0j2A1xR+7Esgbb9z3g+JSR77oZioYzcFbwUtBgfnhj9n9xVtSp95KfY/QFkkUNk)
5. CSS Modules
CSS modules are supported out of the box simply by adding the module attribute in the style tag. The classes are automatically exposed in the template with the $style variable.
<template>
<p :class="$style.red">This should be red</p>
</template>
<style module>
.red {
color: red;
}
</style>
6. Variables in CSS Vs SCSS
SCSS variables were a big revolution in the way we write CSS. Before preprocessors using variables was just not possible. Since then CSS caught-up and CSS variables are now supported in all major browsers. They offer everything that SCSS variables can do and additionally provide easier theming capabilities which makes them a clear winner in this debate.
[More info about CSS vs SCSS variables](https://codyhouse.co/blog/post/css-custom-properties-vs-sass-variables)
7. SCSS include Vs extend
These two SCSS helpers can often cause confusion since they both can be used to reduce SCSS code repetition. There are some subtle differences in the CSS output that you should be aware of.
The @include helper is used to include the code written in a mixin block.
<template>
<p class="error-text">Hello World!</p>
<p class="error-notification">Hello World!</p>
</template>
<style lang="scss">
@mixin error {
color: red;
}
.error-text {
@include error;
font-size: 24px;
}
.error-notification {
@include error;
border: 1px solid red;
padding: 8px;
}
</style>
The produced CSS will have the code duplicated as many times as needed
.error-text {
color: red;
font-size: 24px;
}
.error-notification {
color: red;
border: 1px solid red;
padding: 8px;
}
The
errormixin here is kept to only one rule but normally more complex mixins will exist in a real world application.
On the other hand, @extend is more useful when the elements are almost identical.
<template>
<p class="error-text">Hello World!</p>
<p class="error-notification">Hello World!</p>
</template>
<style lang="scss">
%error {
color: red;
}
.error-text {
@extend %error;
font-size: 24px;
}
.error-notification {
@extend %error;
border: 1px solid red;
padding: 8px;
}
</style>
The produced code is:
.error-notification, .error-text {
color: red;
}
.error-text {
font-size: 24px;
}
.error-notification {
border: 1px solid red;
padding: 8px;
}
The general rule here is to pick extend unless you want to use a parameter with the mixin where onlyinclude will work.
Do you have any useful tips? Please share them in the comments below.

![Better Vue Components with TypeScript [12 examples]](/_astro/img-1.D1-fPpiS_ZnBJgo.webp)
![[Quiz] Dependencies Vs devDependencies](/_astro/img-1.LG0TF6t9_Z1YDO7w.webp)