Scoper
CSS Modules are a popular way to style your websites, but could be easier to use.
Enter, Scoper!
Scoper takes the mapping object tools like WebPack create when you import a CSS Module,
and generates a Tagged Template function that you can use to easily attach the generated class-names to your HTML elements.
Simply tag a template literal containing any valid className
with that function, and Scoper will expand each class-name into its generated equivalent.
Getting Started
Add Scoper to your project using NPM:
> npm install --save @mwm/scoper
Then import Scoper anywhere you're using CSS Modules.
import styles from './App.module.css' // our css
import scoper from '@mwm/scoper' // Scoper!
Scoper won't do anything on it's own;
it needs the mapping object WebPack creates.
Simply pass the imported styles
object to the scoper
function, and Scoper will return a tag function (which we named "scope"):
const scope = scoper(styles)
Tagging function in hand, we can apply complicated scoped classes like this
<div className={scope`my-class otherClass`}>
instead of this
<div className={styles['my-class'] + ' ' + styles.otherClass}>
Finally, you can call the tagging function like a normal function, too!
<div className={scope('my-class otherClass')}>
React Example
This is what the App.js
component might look like if create-react-app used CSS Modules and Scoper tagging.
For this example, I've combined the root <div>
and <header>
elements to show how adding multiple classes works.
I've also renamed the "logo" class to "animated-logo", to show-off how easy kebab class-names are to use.
Finally, the class-names that WebPack generates are configured to include the "App" prefix by default, so I removed that prefix from them.
Here's the code!
import React, { Component } from 'react'
import logo from './logo.svg'
import styles from './App.module.css'
import scoper from '@mwm/scoper'
const scope = scoper(styles)
class App extends Component {
render () {
return (
<header className={scope`root header`}>
<img className={scope`animated-logo`} src={logo} alt='logo' />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className={scope`link`}
href='https://reactjs.org'
target='_blank'
rel='noopener noreferrer'
>
Learn React
</a>
</header>
)
}
}
export default App
Added alternate function, classer
.
You can use the classer named export in React apps to avoid typing out className={scope`whatever`}
.
Instead, combine classer with the spread operator for less typing:
const className = classer(someImportedCSSModule)
const someJSX = <div {...className`something`} />
For example:
import React, { Component } from 'react'
import logo from './logo.svg'
import styles from './App.module.css'
import { classer } from '@mwm/scoper'
const className = classer(styles)
class App extends Component {
render () {
return (
<header {...className`root header`}>
<img {...className`animated-logo`} src={logo} alt='logo' />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
{...className`link`}
href='https://reactjs.org'
target='_blank'
rel='noopener noreferrer'
>
Learn React
</a>
</header>
)
}
}
export default App