CSS on the import statement
CSS module scripts let you load stylesheets through the same import syntax used for JavaScript modules. The feature, available by default in Chrome and Edge 93, treats an imported CSS file as a constructable stylesheet, which can then be attached to a document or shadow root via adoptedStyleSheets. Firefox and Safari support is still in progress, tracked in the Gecko bug and the WebKit bug.
To use a CSS module script, import the file and adopt the resulting default export:
import sheet from './styles.css' assert { type: 'css' };
document.adoptedStyleSheets = [sheet];
shadowRoot.adoptedStyleSheets = [sheet];
Because the imported stylesheet is a constructable stylesheet, applying it works exactly as with manually created ones. The approach removes the need to build <style> elements or assemble CSS strings in JavaScript.
Module semantics carry over
CSS module scripts inherit several guarantees from the JavaScript module system:
- Deduplication: importing the same CSS file from multiple modules fetches, instantiates, and parses it only once.
- Evaluation order: by the time importing JavaScript executes, its stylesheet is already fetched and parsed.
- Security: modules are fetched with CORS and strict MIME-type checking.
The required assert
The assert { type: 'css' } clause is an import assertion and is mandatory. Without it, the browser treats the file as a JavaScript module; an import of a CSS file with a non-JavaScript MIME type will simply fail.
import sheet from './styles.css'; // Failed to load module script:
// Expected a JavaScript module
// script but the server responded
// with a MIME type of "text/css".
The same assertion applies to dynamic imports, where it is passed as a second parameter:
const cssModule = await import('./style.css', {
assert: { type: 'css' }
});
document.adoptedStyleSheets = [cssModule.default];
No @import yet
CSS @import rules are currently unsupported in constructable stylesheets, including CSS module scripts. Any such rules in an imported file are ignored, so an import chain cannot be built this way:
/* atImported.css */
div {
background-color: blue;
}
/* styles.css */
@import url('./atImported.css'); /* Ignored in CSS module */
div {
border: 1em solid green;
}
<!-- index.html -->
<script type="module">
import styles from './styles.css' assert { type: "css" };
document.adoptedStyleSheets = [styles];
</script>
<div>This div will have a green border but no background color.</div>
Support may arrive later; the specification discussion is tracked in the WICG GitHub issue. Familiarity with JavaScript modules before reading on is recommended; the constructable stylesheets guide is also a useful prerequisite. A practical next step is comparing CSS module scripts against older approaches—the notes on performance and memory show some visible gains from using them.



