Styling Vue.js components using CSS

By

Learn the options for styling Vue.js components with CSS, from inline style and dynamic style bindings to scoped style blocks inside single file components.

~~~

Note: this tutorial uses Vue.js Single File Components (Vue 3)

The simplest option to add CSS to a Vue.js component is to use the style tag, just like in HTML:

<template>
  <p style="text-decoration: underline">Hi!</p>
</template>

This is as much static as you can get. What if you want underline to be defined in the component data? Here’s how you can do it:

<template>
  <p :style="{'text-decoration': decoration}">Hi!</p>
</template>

<script setup>
import { ref } from 'vue'

const decoration = ref('underline')
</script>

:style is a shorthand for v-bind:style. I’ll use this shorthand throughout this tutorial.

Notice how we had to wrap text-decoration in quotes. This is because of the dash, which is not part of a valid JavaScript identifier.

You can avoid the quote by using a special camelCase syntax that Vue.js enables, and rewriting it to textDecoration:

<template>
  <p :style="{textDecoration: decoration}">Hi!</p>
</template>

Instead of binding an object to style, you can reference a computed property:

<template>
  <p :style="styling">Hi!</p>
</template>

<script setup>
import { computed, ref } from 'vue'

const textDecoration = ref('underline')
const fontWeight = ref('bold')

const styling = computed(() => {
  return {
    textDecoration: textDecoration.value,
    fontWeight: fontWeight.value
  }
})
</script>

Vue components generate plain HTML, so you can choose to add a class to each element, and add a corresponding CSS selector with properties that style it:

<template>
  <p class="underline">Hi!</p>
</template>

<style>
.underline { text-decoration: underline; }
</style>

You can use SCSS like this:

<template>
  <p class="underline">Hi!</p>
</template>

<style lang="scss">
body {
  .underline { text-decoration: underline; }
}
</style>

You can hardcode the class like in the above example, or you can bind the class to a component property, to make it dynamic, and only apply to that class if the data property is true:

<template>
  <p :class="{underline: isUnderlined}">Hi!</p>
</template>

<script setup>
import { ref } from 'vue'

const isUnderlined = ref(true)
</script>

<style>
.underline { text-decoration: underline; }
</style>

Instead of binding an object to class, like we did with <p :class="{text: isText}">Hi!</p>, you can directly bind a string, and that will reference a data property:

<template>
  <p :class="paragraphClass">Hi!</p>
</template>

<script setup>
import { ref } from 'vue'

const paragraphClass = ref('underline')
</script>

<style>
.underline { text-decoration: underline; }
</style>

You can assign multiple classes either adding two classes to paragraphClass in this case or by using an array:

<template>
  <p :class="[decoration, weight]">Hi!</p>
</template>

<script setup>
import { ref } from 'vue'

const decoration = ref('underline')
const weight = ref('weight')
</script>

<style>
.underline { text-decoration: underline; }
.weight { font-weight: bold; }
</style>

The same can be done using an object inlined in the class binding:

<template>
  <p :class="{underline: isUnderlined, weight: isBold}">Hi!</p>
</template>

<script setup>
import { ref } from 'vue'

const isUnderlined = ref(true)
const isBold = ref(true)
</script>

<style>
.underline { text-decoration: underline; }
.weight { font-weight: bold; }
</style>

And you can combine the two statements:

<template>
  <p :class="[decoration, {weight: isBold}]">Hi!</p>
</template>

<script setup>
import { ref } from 'vue'

const decoration = ref('underline')
const isBold = ref(true)
</script>

<style>
.underline { text-decoration: underline; }
.weight { font-weight: bold; }
</style>

You can also use a computed property that returns an object, which works best when you have many CSS classes to add to the same element:

<template>
  <p :class="paragraphClasses">Hi!</p>
</template>

<script setup>
import { computed, ref } from 'vue'

const isUnderlined = ref(true)
const isBold = ref(true)

const paragraphClasses = computed(() => {
  return {
    underlined: isUnderlined.value,
    bold: isBold.value
  }
})
</script>

<style>
.underlined { text-decoration: underline; }
.bold { font-weight: bold; }
</style>

In the template, refs unwrap automatically. Inside <script setup> you use .value.

Any CSS you bind through :style, unlike the hardcoded first example, is processed by Vue at runtime, and Vue does the nice job of automatically prefixing the CSS for us, so we can write clean CSS while still targeting the browsers Vue 3 supports (modern evergreen browsers, since Vue 3 does not support Internet Explorer).

Scoped styles

Add the scoped attribute to a <style> block in a single file component and Vue limits those rules to that component’s template:

<style scoped>
.underline { text-decoration: underline; }
</style>

Vue rewrites the selectors with a unique data attribute so styles don’t leak into other components.

Tagged: Vue.js · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about vue: