CSS Modules is a popular system for modularizing and composing CSS. vue-loader
provides first-class integration with CSS Modules as an alternative for simulated scoped CSS.
First, CSS Modules must be enabled by passing modules: true
to css-loader
:
// webpack.config.js
{
module: {
rules: [
// ... other rules omitted
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
// enable CSS Modules
modules: true,
// customize generated class names
localIdentName: '[local]_[hash:base64:8]'
}
}
]
}
]
}
}
Then, add the module
attribute to your <style>
:
<style module>
.red {
color: red;
}
.bold {
font-weight: bold;
}
</style>
The module
attribute instructs Vue Loader to inject the CSS modules locals object into the component as a computed property with the name $style
. You can then use it in your templates with a dynamic class binding:
<template>
<p :class="$style.red">
This should be red
</p>
</template>
Since it's a computed property, it also works with the object/array syntax of :class
:
<template>
<div>
<p :class="{ [$style.red]: isRed }">
Am I red?
</p>
<p :class="[$style.red, $style.bold]">
Red and bold
</p>
</div>
</template>
And you can also access it from JavaScript:
<script>
export default {
created () {
console.log(this.$style.red)
// -> "red_1VyoJ-uZ"
// an identifier generated based on filename and className.
}
}
</script>
Refer to the CSS Modules spec for mode details such as global exceptions and composition.
If you only want to use CSS Modules in some of your Vue components, you can use a oneOf
rule and check for the module
string in resourceQuery
:
// webpack.config.js -> module.rules
{
test: /\.css$/,
oneOf: [
// this matches `<style module>`
{
resourceQuery: /module/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]_[hash:base64:5]'
}
}
]
},
// this matches plain `<style>` or `<style scoped>`
{
use: [
'vue-style-loader',
'css-loader'
]
}
]
}
CSS Modules can be used along with other pre-processors:
// webpack.config.js -> module.rules
{
test: /\.scss$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: { modules: true }
},
'sass-loader'
]
}
You can have more than one <style>
tags in a single *.vue
component. To avoid injected styles to overwrite each other, you can customize the name of the injected computed property by giving the module
attribute a value:
<style module="a">
/* identifiers injected as a */
</style>
<style module="b">
/* identifiers injected as b */
</style>