Overview
style-loader injects CSS into the DOM by adding <style> tags. Itβs typically used during development to enable hot module replacement for CSS. For production, use MiniCssExtractPlugin to extract CSS into separate files.
This is an external loader maintained by the webpack team. Install it from npm to use in your webpack configuration.
Installation
npm install -D style-loader css-loader
Basic Usage
webpack.config.js
app.js
styles.css
module . exports = {
module: {
rules: [
{
test: / \. css $ / i ,
use: [ 'style-loader' , 'css-loader' ]
}
]
}
};
style-loader is chained with css-loader. The css-loader interprets @import and url(), then style-loader injects the result into the DOM.
How It Works
When you import a CSS file:
css-loader processes the CSS and resolves imports/URLs
style-loader creates a <style> tag with the CSS content
The <style> tag is injected into the document <head>
Hot Module Replacement (HMR) updates styles without page reload
Options
injectType
Control how styles are injected:
{
loader : 'style-loader' ,
options : {
injectType : 'styleTag' // default
}
}
Available values:
styleTag - Injects <style> tag (default)
singletonStyleTag - Single <style> tag for all CSS
lazyStyleTag - Lazy load styles
lazySingletonStyleTag - Lazy load with single tag
linkTag - Injects <link> tag
attributes
Add custom attributes to style tags:
{
loader : 'style-loader' ,
options : {
attributes : {
id : 'my-styles' ,
'data-app' : 'my-app'
}
}
}
Generates:
< style id = "my-styles" data-app = "my-app" >
/* CSS here */
</ style >
Customize where styles are inserted:
{
loader : 'style-loader' ,
options : {
insert : 'head' // default
}
}
Or use a function:
{
loader : 'style-loader' ,
options : {
insert : function ( element ) {
// Insert before other styles
var parent = document . querySelector ( 'head' );
var lastInsertedElement = window . _lastInsertedElement || parent . querySelector ( 'style' );
if ( ! lastInsertedElement ) {
parent . insertBefore ( element , parent . firstChild );
} else if ( lastInsertedElement . nextSibling ) {
parent . insertBefore ( element , lastInsertedElement . nextSibling );
} else {
parent . appendChild ( element );
}
window . _lastInsertedElement = element ;
}
}
}
Customize how CSS is applied to the style tag:
{
loader : 'style-loader' ,
options : {
styleTagTransform : function ( css , style ) {
// Custom transformation
style . innerHTML = css ;
}
}
}
Advanced Usage
Lazy Loading Styles
{
test : / \. lazy \. css $ / i ,
use : [
{
loader: 'style-loader' ,
options: {
injectType: 'lazyStyleTag'
}
},
'css-loader'
]
}
import styles from './styles.lazy.css' ;
// Styles are not injected yet
styles . use (); // Inject styles
styles . unuse (); // Remove styles
Singleton Style Tag
Use a single <style> tag for all CSS:
{
loader : 'style-loader' ,
options : {
injectType : 'singletonStyleTag'
}
}
Singleton mode can improve performance when you have many CSS modules.
Custom Insertion Point
{
loader : 'style-loader' ,
options : {
insert : function ( element ) {
var target = document . querySelector ( '#app-styles' );
target . appendChild ( element );
}
}
}
Development vs Production
Use style-loader in development and MiniCssExtractPlugin in production for better performance.
Development
Production
Dynamic (Recommended)
module . exports = {
mode: 'development' ,
module: {
rules: [
{
test: / \. css $ / ,
use: [ 'style-loader' , 'css-loader' ]
}
]
}
};
Hot Module Replacement
style-loader works seamlessly with HMR:
module . exports = {
devServer: {
hot: true
},
module: {
rules: [
{
test: / \. css $ / ,
use: [ 'style-loader' , 'css-loader' ]
}
]
}
};
CSS changes are reflected immediately without page reload.
Common Patterns
With CSS Modules
{
test : / \. module \. css $ / ,
use : [
'style-loader' ,
{
loader: 'css-loader' ,
options: {
modules: true
}
}
]
}
With PostCSS
{
test : / \. css $ / ,
use : [
'style-loader' ,
{
loader: 'css-loader' ,
options: {
importLoaders: 1
}
},
'postcss-loader'
]
}
With Sass
{
test : / \. scss $ / ,
use : [
'style-loader' ,
'css-loader' ,
'sass-loader'
]
}
Development
Fast rebuilds with HMR
No need to extract CSS to files
Styles update without page reload
Production
Use MiniCssExtractPlugin instead
Enables CSS caching
Reduces JavaScript bundle size
Allows parallel loading of CSS and JS
Common Issues
Issue: Flash of Unstyled Content (FOUC)
Cause: Styles are injected after JavaScript executes.
Solution: Use MiniCssExtractPlugin in production:
use : [ MiniCssExtractPlugin . loader , 'css-loader' ]
Issue: Styles Not Updating
Cause: HMR not enabled or style-loader not properly configured.
Solution: Ensure HMR is enabled:
Solution: Use singletonStyleTag:
{
loader : 'style-loader' ,
options : {
injectType : 'singletonStyleTag'
}
}
Issue: Conflicts with Content Security Policy (CSP)
Solution: Use nonce attribute:
{
loader : 'style-loader' ,
options : {
attributes : {
nonce : '__webpack_nonce__'
}
}
}
Set nonce in your entry file:
__webpack_nonce__ = 'random-nonce-value' ;
Browser Compatibility
style-loader works in all modern browsers that support:
document.createElement
document.head.appendChild
style.innerHTML
IE9+ is supported.
Resources