vite-plugin-css-modules
A Vite plugin that turns
import styles from './file.css' with { type: 'css' };into either a constructable CSSStyleSheet (when supported) or the raw CSS string as a fallback — with optional enforcement of type="css" and smooth HMR behavior.
Overview
Modern browsers support constructable stylesheets via new CSSStyleSheet() and document.adoptedStyleSheets, which enables:
- fast style application without injecting
<style>tags - cheap swaps on update (nice for HMR)
- easier style scoping / sharing patterns (especially in web components)
This plugin makes authoring simple: you keep importing plain .css files from JS/TS, and the plugin rewrites those imports so that:
- the CSS is bundled as an inline string (
?inline) - the module’s default export becomes:
- a
CSSStyleSheetinstance (preferred, when available in the runtime), or - the original CSS string (fallback) for older browsers and Node.js environments
- a
It also optionally supports a stricter mode where it only transforms CSS imports that explicitly declare type="css" in the import attributes.
Install
npm i -D @chialab/vite-plugin-css-modulesyarn add -D @chialab/vite-plugin-css-modulespnpm add -D @chialab/vite-plugin-css-modulesConfiguration
Add the plugin to your Vite config:
import cssModulesPlugin from '@chialab/vite-plugin-css-modules';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
cssModulesPlugin({
checkAttribute: false,
include: '**/*.{js,jsx,ts,tsx}',
}),
],
});{
"compilerOptions": {
"types": ["@chialab/vite-plugin-css-modules/vite"]
}
}Options
checkAttribute
Type: boolean
Default: true
If true, only imports with with { type: 'css' } will be transformed. If false, all .css imports in the include option will be transformed.
WARNING
Set this option to false until Vite has a proper support for import attributes.
include and exclude
Type: string | string[]
Default: **/*.{js,jsx,ts,tsx}
Specify which files to transform (or not) using globs patterns. By default, all JS and TS files are included.
Examples
Basic usage
import styles from './styles.css' with { type: 'css' };
document.adoptedStyleSheets = [styles];Web Component usage
import styles from './my-component.css' with { type: 'css' };
class MyComponent extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
shadow.adoptedStyleSheets = [styles];
shadow.innerHTML = `<div>Hello, world!</div>`;
}
}Handle fallback for older browsers
import styles from './styles.css' with { type: 'css' };
if ('adoptedStyleSheets' in Document.prototype) {
document.adoptedStyleSheets = [styles];
} else {
const styleTag = document.createElement('style');
styleTag.textContent = styles;
document.head.appendChild(styleTag);
}