Style Loader

[![npm][npm]][npm-url] [![node][node]][node-url] [![tests][tests]][tests-url] [![coverage][cover]][cover-url] [![discussion][discussion]][discussion-url] [![size][size]][size-url] # style-loader Inject CSS into the DOM. ## Getting Started To begin, you'll need to install `style-loader`: ```console npm install --save-dev style-loader ``` or ```console yarn add -D style-loader ``` or ```console pnpm add -D style-loader ``` It's recommended to combine `style-loader` with the [`css-loader`](https://github.com/webpack-contrib/css-loader) Then add the loader to your `webpack` config. For example: **style.css** ```css body { background: green; } ``` **component.js** ```js import "./style.css"; ``` **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: ["style-loader", "css-loader"], }, ], }, }; ``` ## Security Warning This loader is primarily meant for development. The default settings are not safe for production environments. See the [recommended example configuration](#recommended) and the section on [nonces](#nonce) for details. ## Options - [**`injectType`**](#injecttype) - [**`attributes`**](#attributes) - [**`insert`**](#insert) - [**`styleTagTransform`**](#styleTagTransform) - [**`base`**](#base) - [**`esModule`**](#esmodule) ### `injectType` Type: ```ts type injectType = | "styleTag" | "singletonStyleTag" | "autoStyleTag" | "lazyStyleTag" | "lazySingletonStyleTag" | "lazyAutoStyleTag" | "linkTag"; ``` Default: `styleTag` Allows to setup how styles will be injected into the DOM. Possible values: #### `styleTag` Automatically injects styles into the DOM using multiple ``. It is **default** behaviour. **component.js** ```js import "./styles.css"; ``` Example with Locals (CSS Modules): **component-with-css-modules.js** ```js import styles from "./styles.css"; const divElement = document.createElement("div"); divElement.className = styles["my-class"]; ``` All locals (class names) stored in imported object. **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: [ // The `injectType` option can be avoided because it is default behaviour { loader: "style-loader", options: { injectType: "styleTag" } }, "css-loader", ], }, ], }, }; ``` The loader inject styles like: ```html ``` #### `singletonStyleTag` Automatically injects styles into the DOM using one ``. > **Warning** > > Source maps do not work. **component.js** ```js import "./styles.css"; ``` **component-with-css-modules.js** ```js import styles from "./styles.css"; const divElement = document.createElement("div"); divElement.className = styles["my-class"]; ``` All locals (class names) stored in imported object. **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: [ { loader: "style-loader", options: { injectType: "singletonStyleTag" }, }, "css-loader", ], }, ], }, }; ``` The loader inject styles like: ```html ``` #### `autoStyleTag` Works the same as a [`styleTag`](#styleTag), but if the code is executed in IE6-9, turns on the [`singletonStyleTag`](#singletonStyleTag) mode. #### `lazyStyleTag` Injects styles into the DOM using multiple `` on demand. We recommend following `.lazy.css` naming convention for lazy styles and the `.css` for basic `style-loader` usage (similar to other file types, i.e. `.lazy.less` and `.less`). When you `lazyStyleTag` value the `style-loader` injects the styles lazily making them useable on-demand via `style.use()` / `style.unuse()`. > ⚠️ Behavior is undefined when `unuse` is called more often than `use`. Don't do that. **component.js** ```js import styles from "./styles.lazy.css"; styles.use(); // For removing styles you can use // styles.unuse(); ``` **component-with-css-modules.js** ```js import styles from "./styles.lazy.css"; styles.use(); const divElement = document.createElement("div"); divElement.className = styles.locals["my-class"]; ``` All locals (class names) stored in `locals` property of imported object. **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, exclude: /\.lazy\.css$/i, use: ["style-loader", "css-loader"], }, { test: /\.lazy\.css$/i, use: [ { loader: "style-loader", options: { injectType: "lazyStyleTag" } }, "css-loader", ], }, ], }, }; ``` The loader inject styles like: ```html ``` #### `lazySingletonStyleTag` Injects styles into the DOM using one `` on demand. We recommend following `.lazy.css` naming convention for lazy styles and the `.css` for basic `style-loader` usage (similar to other file types, i.e. `.lazy.less` and `.less`). When you `lazySingletonStyleTag` value the `style-loader` injects the styles lazily making them useable on-demand via `style.use()` / `style.unuse()`. > ⚠️ Source maps do not work. > ⚠️ Behavior is undefined when `unuse` is called more often than `use`. Don't do that. **component.js** ```js import styles from "./styles.css"; styles.use(); // For removing styles you can use // styles.unuse(); ``` **component-with-css-modules.js** ```js import styles from "./styles.lazy.css"; styles.use(); const divElement = document.createElement("div"); divElement.className = styles.locals["my-class"]; ``` All locals (class names) stored in `locals` property of imported object. **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, exclude: /\.lazy\.css$/i, use: ["style-loader", "css-loader"], }, { test: /\.lazy\.css$/i, use: [ { loader: "style-loader", options: { injectType: "lazySingletonStyleTag" }, }, "css-loader", ], }, ], }, }; ``` The loader generate this: ```html ``` #### `lazyAutoStyleTag` Works the same as a [`lazyStyleTag`](#lazyStyleTag), but if the code is executed in IE6-9, turns on the [`lazySingletonStyleTag`](#lazySingletonStyleTag) mode. #### `linkTag` Injects styles into the DOM using multiple `` . > ℹ️ The loader will dynamically insert the `` tag at runtime via JavaScript. You should use [MiniCssExtractPlugin](https://webpack.js.org/plugins/mini-css-extract-plugin/) if you want to include a static ``. ```js import "./styles.css"; import "./other-styles.css"; ``` **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.link\.css$/i, use: [ { loader: "style-loader", options: { injectType: "linkTag" } }, { loader: "file-loader" }, ], }, ], }, }; ``` The loader generate this: ```html ``` ### `attributes` Type: ```ts type attributes = HTMLAttributes; ``` Default: `{}` If defined, the `style-loader` will attach given attributes with their values on ` ``` ### `insert` Type: ```ts type insert = | string | ((htmlElement: HTMLElement, options: Record) => void); ``` Default: `head` By default, the `style-loader` appends `` and works faster. > **Warning** > > Do not use together `style-loader` and `mini-css-extract-plugin`. **webpack.config.js** ```js const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const devMode = process.env.NODE_ENV !== "production"; module.exports = { module: { rules: [ { test: /\.(sa|sc|c)ss$/, use: [ devMode ? "style-loader" : MiniCssExtractPlugin.loader, "css-loader", "postcss-loader", "sass-loader", ], }, ], }, plugins: [].concat(devMode ? [] : [new MiniCssExtractPlugin()]), }; ``` ### Named export for CSS Modules > **Warning** > > Names of locals are converted to `camelCase`. > **Warning** > > It is not allowed to use JavaScript reserved words in css class names. > **Warning** > > Options `esModule` and `modules.namedExport` in `css-loader` should be enabled. **styles.css** ```css .foo-baz { color: red; } .bar { color: blue; } ``` **index.js** ```js import { fooBaz, bar } from "./styles.css"; console.log(fooBaz, bar); ``` You can enable a ES module named export using: **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/, use: [ { loader: "style-loader", }, { loader: "css-loader", options: { modules: { namedExport: true, }, }, }, ], }, ], }, }; ``` ### Source maps The loader automatically inject source maps when previous loader emit them. Therefore, to generate source maps, set the `sourceMap` option to `true` for the previous loader. **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: [ "style-loader", { loader: "css-loader", options: { sourceMap: true } }, ], }, ], }, }; ``` ### Nonce If you are using a [Content Security Policy](https://www.w3.org/TR/CSP3/) (CSP), the injected code will usually be blocked. A workaround is to use a nonce. Note, however, that using a nonce significantly reduces the protection provided by the CSP. You can read more about the security impact in [the specification](https://www.w3.org/TR/CSP3/#security-considerations). The better solution is not to use this loader in production. There are two ways to work with `nonce`: - using the `attributes` option - using the `__webpack_nonce__` variable > **Warning** > > the `attributes` option takes precedence over the `__webpack_nonce__` variable #### `attributes` **component.js** ```js import "./style.css"; ``` **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: [ { loader: "style-loader", options: { attributes: { nonce: "12345678", }, }, }, "css-loader", ], }, ], }, }; ``` The loader generate: ```html ``` #### `__webpack_nonce__` **create-nonce.js** ```js __webpack_nonce__ = "12345678"; ``` **component.js** ```js import "./create-nonce.js"; import "./style.css"; ``` Alternative example for `require`: **component.js** ```js __webpack_nonce__ = "12345678"; require("./style.css"); ``` **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: ["style-loader", "css-loader"], }, ], }, }; ``` The loader generate: ```html ``` #### Insert styles at top Inserts styles at top of `head` tag. **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: [ { loader: "style-loader", options: { insert: function insertAtTop(element) { var parent = document.querySelector("head"); var lastInsertedElement = window._lastElementInsertedByStyleLoader; if (!lastInsertedElement) { parent.insertBefore(element, parent.firstChild); } else if (lastInsertedElement.nextSibling) { parent.insertBefore(element, lastInsertedElement.nextSibling); } else { parent.appendChild(element); } window._lastElementInsertedByStyleLoader = element; }, }, }, "css-loader", ], }, ], }, }; ``` #### Insert styles before target element Inserts styles before `#id` element. **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: [ { loader: "style-loader", options: { insert: function insertBeforeAt(element) { const parent = document.querySelector("head"); const target = document.querySelector("#id"); const lastInsertedElement = window._lastElementInsertedByStyleLoader; if (!lastInsertedElement) { parent.insertBefore(element, target); } else if (lastInsertedElement.nextSibling) { parent.insertBefore(element, lastInsertedElement.nextSibling); } else { parent.appendChild(element); } window._lastElementInsertedByStyleLoader = element; }, }, }, "css-loader", ], }, ], }, }; ``` #### Custom Elements (Shadow DOM) You can define custom target for your styles for the `lazyStyleTag` type. **webpack.config.js** ```js module.exports = { module: { rules: [ { test: /\.css$/i, use: [ { loader: "style-loader", options: { injectType: "lazyStyleTag", // Do not forget that this code will be used in the browser and // not all browsers support latest ECMA features like `let`, `const`, `arrow function expression` and etc, // we recommend use only ECMA 5 features, // but it is depends what browsers you want to support insert: function insertIntoTarget(element, options) { var parent = options.target || document.head; parent.appendChild(element); }, }, }, "css-loader", ], }, ], }, }; ``` Insert styles to the provided element or to the `head` tag if target isn't provided. **custom-square.css** ```css div { width: 50px; height: 50px; background-color: red; } ``` **custom-square.js** ```js import customSquareStyles from "./custom-square.css"; class CustomSquare extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); const divElement = document.createElement("div"); divElement.textContent = "Text content."; this.shadowRoot.appendChild(divElement); customSquareStyles.use({ target: this.shadowRoot }); // You can override injected styles const bgPurple = new CSSStyleSheet(); const width = this.getAttribute("w"); const height = this.getAttribute("h"); bgPurple.replace(`div { width: ${width}px; height: ${height}px; }`); this.shadowRoot.adoptedStyleSheets = [bgPurple]; // `divElement` will have `100px` width, `100px` height and `red` background color } } customElements.define("custom-square", CustomSquare); export default CustomSquare; ``` ## Contributing Please take a moment to read our contributing guidelines if you haven't yet done so. [CONTRIBUTING](./.github/CONTRIBUTING.md) ## License [MIT](./LICENSE) [npm]: https://img.shields.io/npm/v/style-loader.svg [npm-url]: https://npmjs.com/package/style-loader [node]: https://img.shields.io/node/v/style-loader.svg [node-url]: https://nodejs.org [tests]: https://github.com/webpack-contrib/style-loader/workflows/style-loader/badge.svg [tests-url]: https://github.com/webpack-contrib/style-loader/actions [cover]: https://codecov.io/gh/webpack-contrib/style-loader/branch/master/graph/badge.svg [cover-url]: https://codecov.io/gh/webpack-contrib/style-loader [discussion]: https://img.shields.io/github/discussions/webpack/webpack [discussion-url]: https://github.com/webpack/webpack/discussions [size]: https://packagephobia.now.sh/badge?p=style-loader [size-url]: https://packagephobia.now.sh/result?p=style-loader