If you are considering to use
react-css-modules , evaluate if
babel-plugin-react-css-modules covers your use case.
babel-plugin-react-css-modules is a lightweight alternative of
react-css-modules .
babel-plugin-react-css-modules is not a drop-in replacement and does not cover all the use cases of
react-css-modules . However, it has a lot smaller performance overhead (0-10% vs +50%; see Performance ) and a lot smaller size footprint (less than 2kb vs +17kb).
It is easy to get started! See the demo https://github.com/gajus/babel-plugin-react-css-modules/tree/master/demo
-
CSS Modules -
What's the Problem? -
The Implementation -
Usage -
SASS, SCSS, LESS and other CSS Preprocessors -
Class Composition -
Global CSS -
Multiple CSS Modules
import React from 'react' ;
import styles from './ table.css' ;
export default class Table extends React . Component {
render ( ) {
return < div className = { styles . table } >
< div className = { styles . row } >
< div className = { styles . cell } > A0 < / div >
< div className = { styles . cell } > B0 < / div >
< / div >
< / div > ;
}
}
< div class = "table__table___32osj" >
< div class = "table__row___2w27N" >
< div class = "table__cell___1oVw5" > A0 < / div >
< div class = "table__cell___1oVw5" > B0 < / div >
< / div >
< / div >
-
You have to use camelCase CSS class names. -
You have to use styles object whenever constructing a className . -
Mixing CSS Modules and global CSS classes is cumbersome. -
Reference to an undefined CSS Module resolves to undefined without a warning.
import React from 'react' ;
import CSSModules from 'react-css-modules' ;
import styles from './ table.css' ;
class Table extends React . Component {
render ( ) {
return < div styleName = 'table' >
< div styleName = 'row' >
< div styleName = 'cell' > A0 < / div >
< div styleName = 'cell' > B0 < / div >
< / div >
< / div > ;
}
}
export default CSSModules ( Table , styles ) ;
-
You are not forced to use the camelCase naming convention. -
You do not need to refer to the styles object every time you use a CSS Module. -
There is clear distinction between global CSS and CSS Modules, e.g.
< div className = 'global-css' styleName = 'local-module' > < / div >
-
You are warned when styleName refers to an undefined CSS Module ( handleNotFoundStyleName option). -
You can enforce use of a single CSS module per ReactElement ( allowMultiple option).
-
Setting up a module bundler to load the Interoperable CSS . -
Decorating your component using react-css-modules .
-
Install style-loader . -
Install css-loader . -
Setup /\.css$/ loader:
{
test : / \.css$ / ,
loaders : [
'style-loader? sourceMap' ,
'css-loader? modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
]
}
Advantages:
Fewer style tags (older IE has a limit) CSS SourceMap (with
devtool: "source-map" and
css-loader?sourceMap ) CSS requested in parallel CSS cached separate Faster runtime (less code and DOM operations)
Caveats:
Additional HTTP request Longer compilation time More complex configuration No runtime public path modification No Hot Module Replacement
-
Install style-loader . -
Install css-loader . -
Use extract-text-webpack-plugin to extract chunks of CSS into a single stylesheet. -
Setup /\.css$/ loader: -
ExtractTextPlugin v1x: { test : / \.css$ / , loader : ExtractTextPlugin . extract ( 'style' , 'css? modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]' ) } -
ExtractTextPlugin v2x: { test : / \.css$ / , use : ExtractTextPlugin . extract ( { fallback : 'style-loader' , use : 'css-loader? modules,localIdentName="[name]-[local]-[hash:base64:6]"' } ) , }
-
-
Setup extract-text-webpack-plugin plugin: -
ExtractTextPlugin v1x: new ExtractTextPlugin ( 'app.css' , { allChunks : true } ) -
ExtractTextPlugin v2x: new ExtractTextPlugin ( { filename : 'app.css' , allChunks : true } )
-
import React from 'react' ;
import CSSModules from 'react-css-modules' ;
import styles from './ table.css' ;
class Table extends React . Component {
render ( ) {
return < div styleName = 'table' >
< div styleName = 'row' >
< div styleName = 'cell' > A0 < / div >
< div styleName = 'cell' > B0 < / div >
< / div >
< / div > ;
}
}
export default CSSModules ( Table , styles ) ;
import customStyles from './ table-custom-styles.css' ;
< Table styles = { customStyles } / > ;
/* table-custom-styles.css */ . table { composes : table from './ table.css' ; } . row { composes : row from './ table.css' ; } /* .cell {
composes: cell from './table.css';
} */ . table { width : four hundred px ; } . cell { float : left; width : one hundred and fifty-four px ; background : # eee ; padding : ten px ; margin : ten px zero ten px ten px ; }
class extends React . Component {
render ( ) {
< div >
< p styleName = 'foo' > < / p >
< p className = { this . props . styles . foo } > < / p >
< / div > ;
}
}
import React from 'react' ;
import CSSModules from 'react-css-modules' ;
import List from './ List' ;
import styles from './ table.css' ;
class CustomList extends React . Component {
render ( ) {
let itemTemplate ;
itemTemplate = ( name ) => {
return < li styleName = 'item-template' > { name } < / li > ;
} ;
return < List itemTemplate = { itemTemplate } / > ;
}
}
export default CSSModules ( CustomList , styles ) ;
import React from 'react' ;
import CSSModules from 'react-css-modules' ;
import List from './ List' ;
import styles from './ table.css' ;
class CustomList extends React . Component {
render ( ) {
let itemTemplate ;
itemTemplate = ( name ) => {
return < li className = { this . props . styles [ 'item-template' ] } > { name } < / li > ;
} ;
return < List itemTemplate = { itemTemplate } / > ;
}
}
export default CSSModules ( CustomList , styles ) ;
import React from 'react' ;
import CSSModules from 'react-css-modules' ;
import List from './ List' ;
import styles from './ table.css' ;
class CustomList extends React . Component {
render ( ) {
let itemTemplate ;
itemTemplate = ( name ) => {
return < li styleName = 'item-template' > { name } < / li > ;
} ;
itemTemplate = CSSModules ( itemTemplate , this . props . styles ) ;
return < List itemTemplate = { itemTemplate } / > ;
}
}
export default CSSModules ( CustomList , styles ) ;
/**
* @typedef CSSModules~Options
* @see {@link https://github.com/gajus/react-css-modules#options }
* @property {Boolean} allowMultiple
* @property {String} handleNotFoundStyleName
*/
/**
* @param {Function} Component
* @param {Object} defaultStyles CSS Modules class map.
* @param {CSSModules~Options} options
* @return {Function}
*/
import React from 'react' ;
import CSSModules from 'react-css-modules' ;
import styles from './ table.css' ;
class Table extends React . Component {
render ( ) {
return < div styleName = 'table' >
< div styleName = 'row' >
< div styleName = 'cell' > A0 < / div >
< div styleName = 'cell' > B0 < / div >
< / div >
< / div > ;
}
}
export default CSSModules ( Table , styles ) ;
import React from 'react' ;
import CSSModules from 'react-css-modules' ;
import styles from './ table.css' ; @ CSSModules ( styles )
export default class extends React . Component {
render ( ) {
return < div styleName = 'table' >
< div styleName = 'row' >
< div styleName = 'cell' > A0 < / div >
< div styleName = 'cell' > B0 < / div >
< / div >
< / div > ;
}
}
CSSModules ( Component , styles , options ) ;
@ CSSModules ( styles , options ) ;
< div styleName = 'foo bar' / >
throw throws an error log logs a warning using console.warn ignore silently ignores the missing style name
{
test : / \.scss$ / ,
loaders : [
'style' ,
'css? modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]' ,
'resolve-url' ,
'sass'
]
}
{
test : / \.scss$ / ,
loaders : [
'style? sourceMap' ,
'css? modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]' ,
'resolve-url' ,
'sass? sourceMap'
]
}
. box { width : one hundred px ; height : one hundred px ; } . empty { composes : box; background : # 4CAF50 ; } . full { composes : box; background : # F44336 ; }
. box { width : one hundred px ; height : one hundred px ; } . box-empty { background : # 4CAF50 ; } . box-full { background : # F44336 ; }
< div class =' box box-empty ' > </ div >
% box { width : one hundred px ; height : one hundred px ; } . box-empty { @extend %box; background : # 4CAF50 ; } . box-full { @extend %box; background : # F44336 ; }
. box-empty , . box-full { width : one hundred px ; height : one hundred px ; } . box-empty { background : # 4CAF50 ; } . box-full { background : # F44336 ; }
@mixin box { width : one hundred px ; height : one hundred px ; } . box-empty { @include box; background : # 4CAF50 ; } . box-full { @include box; background : # F44336 ; }
. box-empty { width : one hundred px ; height : one hundred px ; background : # 4CAF50 ; } . box-full { width : one hundred px ; height : one hundred px ; background : # F44336 ; }
: global . foo { }
. button { } . active { }
< div styleName = 'button active' > < / div >