DEV Community

Cover image for CSS Modules in Vue.js
Frida Nyvall
Frida Nyvall

Posted on • Edited on • Originally published at redonion.se

CSS Modules in Vue.js

Part three in a series of articles about working with CSS in Vue.js, focusing on using CSS Modules in Vue.js.

In these types of javascript frameworks, it has become popular to use CSS Modules. It is a way of automatically creating unique class names, thereby preventing any possible style leaking or accidental cascading between elements.

Support for CSS Modules is already setup by default by the Vue CLI.

In the .vue file where you want to use CSS modules, add module to the style tag:

<style module>
  .hello{
    background-color: mistyrose;
  }
</style>

In the .vue file template, the class name is then added though javascript:

<div :class="$style.hello">

The $style prefix used in .vue file templates refers to any styles within the component (.vue file) style tag.

Targeting Elements Without Defined Class Names

For targeting HTML elements without defined class names like p or h1, you would have to make sure they are related to their parent for them to be included in the module class name output.

In the example below, the h3 style text-decoration underline will be added to the CSS as .hello-[modulename-identifier] h3. The h3 outside of the .hello block will not be included in the .hello-[modulename-identifier] block and therefore risk affecting other h3 tags outside of the module.

<style module>
  .hello{
    background-color: mistyrose;
  }

  .hello h3{
    text-decoration: underline;
  }

  h3{
    margin: 1em 0;
  }
</style>

Changing the Class Name

If you want to change the generated module class names, this can be done in the vue.config.js file:

module.exports = {
  css: {
    loaderOptions: {
      css: {
        localIdentName: '[local][Frida][hash:base64:8]'
        // camelCase: 'only' //optional setting for how the name is output
      }
    }
  }
}

In the example above, I’ve added my name Frida followed by a random string to make sure the name is unique.

Utilizing the Class Name

It is possible to use the expression $style.hello as a reference to the class name elsewhere within the vue component.

<p>Printing $style.hello: {{ $style.hello }}</p>

The code above will output: “Printing $style.hello: hello-[modulename-identifier]”

This can also be used to for example target the element using JavaScript, access and print out its styles or do any other operation. Because of the module naming convention, the class name acts like an ID meaning there will be just one element with this specific name.

Example: Outputting an Element Style

A very basic example where an element’s background-color is output.
In the .vue file template section:

<p>Output: {{ $style.hello }} background-color is: {{ dataBackground }}</p>
<!-- Output: hello-[modulename-indentifier] background-color is: #ffe4e1 -->

In the .vue file script section:

<script>
export default {
  data () {
    return {
      dataBackground: 'background'
    }
  },
  methods: {
    classNameBackground () {
      const elem = document.getElementsByClassName(this.$style.hello)[0]
      const compStyles = window.getComputedStyle(elem)
      const bg = compStyles.getPropertyValue('background-color')

      this.dataBackground = bg
      return bg
    }
  },
  mounted () {
    this.classNameBackground()
  }
}
</script>

In the .vue file style section:

<style module>
  .hello{
    background-color: #ffe4e1;
  }
</style>

CSS Modules :export

Another way of accessing information in the CSS style block is to use the :export feature in CSS Modules to export strings from the style tag:

<template>
    <p>{{ $style.primaryColor }}</p>
    <!-- Outputs: #ffe4e1 -->
    <p>{{ $style.displayAs }}</p>
    <!-- Outputs: some-string -->
</template>

<style module lang=”scss”>
  $primary-color: #ffe4e1;

  :export {
    primaryColor: $primary-color;
    displayAs: some-string;
  }
</style>

Note that the :export feature seems restricted to working with strings. To get a specific CSS style from a named class, it might be better to go the JavaScript route as per the example above.

Read more about the :export feature in the CSS Modules documentation, and more about CSS Modules in Vue, in the vue-loader documentation.

Importing Module Style Files

For when you want to place your CSS Module styles in separate files, rather than in the style tag in each .vue component file.

Create your style file and place it for example in the same folder as your component. Name it “filename.module.fileextension”. In my example, I’ve created the style file “HelloWorld.module.scss”. In HelloWorld.module.scss:

.imported{
    background-color:green;
}

Import the style file in the script tag of the component where you want to use it, in this example HelloWorld.vue. I found that I also had to add the import to data:

<script>
  import scssStyles from './HelloWorld.module.scss'
  export default {
    data () {
      return {
        scssStyles
      }
    }
  }
</script>

In the template part of your component, add the class by referencing the import name and the class name in the style file:

<template>
  <p :class="scssStyles.imported">
</template>

Make all CSS Files CSS Modules

If you want to be able to omit the extra “.module” in the file name, you can add this setting to the vue.config.js file:

module.exports = {
  css: {
    modules: true
  }
}

However setting modules to true will at the same time also cause all other style files to be working as CSS modules.

Note that the imported .module.scss file content is not available to the vue file component style tag, since the generated class names will differ. Also note that variables inside the imported file are not available to the component style tag. To achieve this, see the article “Importing Style Files to Component Style Tags in Vue.js”.


Setup

The starting code for this article is created by the Vue CLI command tool version 3.3.0 and Vue.js version 2.6.10. Note that both setup, plugins and framework are evolving. Changes will in time most certainly happen that make the techniques described in this post less relevant.


Top comments (2)

Collapse
 
liyasthomas profile image
Liyas Thomas

Hi Frida.
Taking this thread from dev.to article series on Vue & CSS. The articles are great 🎉

We're team behind postwoman.io - A free, fast & beautiful alternative to Postman built with Vue Nuxt. It's 100% open sourced github.com/liyasthomas/postwoman and community driven (6,100+ stars in 1.5 months, #2 product of the day on Product Hunt • featured in Indie Hackers, Hacker news, Hacker noon, YouTube & open source dev podcast etc.).

We would love to have contributions from people like you. Suggestions/contributions from you would be an asset for the project.

Collapse
 
fridanyvall profile image
Frida Nyvall

Thank you for your kind words. Postwoman.io seems really cool! :)