react-stylescope
v0.9.3
Published
Component based styling for react. Write styles that are scoped to the components where they are created.
Downloads
15
Readme
react-stylescope
Component based styling for react. Write styles that are scoped to the components where they are created.
A react implementation of the @scope
CSS at-rule with support for all browsers that can run JavaScript.
React allows you to write components to define your app's UI. Every component have its own logic and state
which allows for a dclarative and mantainable codebase. However, how do we style those components? What if
the are differnt teams working on different parts of the application? How do we solve the confusion of CSS
name conflicts easily? Team A sets .card{ background-color: white;}
Team B thinks .card{ background-color: blue;}
works perfectly for them. Both Teams push to production. What happens next? Disaster!!
There are solutions like styled-components. Styled-components is one of the good solutions out there to help write styles that are scoped or tied to components. However, wouldn't it be easier to write styles with auto completions out of the box than writing as strings?
All you will need to do is npm install react-stylescope
Write your style-scopped component.
import { useScopedStyleSheet, getScopedName, ScopedStyleSheets } from 'react-stylescope'
type CardProps = {backgroundColor: 'white'|'blue',caption:string}
const Card = ({backgroundColor, caption}: CardProps)=>{
const scoped = getScopedName('Card')
const { keys, sheet } = useScopedStyleSheet({
'.card-container': {
width: '320px',
backgroundColor: `${backgroundColor}`
},
'.card-container img':{
lineHeight: 1.5,
display: 'block',
margin: '10px'
}
}, scoped)
return (
<div className={keys['.card-container']} >
<div><img src='image.png' alt='Some text' /></div>
<div>{caption}</div>
<ScopedStyleSheets styles={sheet} />
</div>
)
}
Now from the above component, Team A and Team B can use their desired color for background without anymore worries.
And, relax. The style object passed to useScopedStyleSheet
does not get to the browser. Hurray! It's transpiled
into strings before the code gets served to the browser. You get what I'm heading to right? Write the styles with
code completions and it's converted into strings for you. No more pain writing css in strings.
How to use react-stylescope
After installation, if the project was created with create-react-app
navigate to the project directory and run
npx stylescope --setup react
Else, add the code below to the end of the module.rules
array in the webpack.config.js
and run npx stylescope --setup device
{
test:/(\.ts|\.js|\.cjs|\.mjs|\.tsx|\.jsx)$/,
exclude:/node_modules/,
loader: require.resolve('react-stylescope/dist/lib/loader.js')
}
Using Vite?
Import the ScopedStyleVitePlugin
and add to the plugins array in the vite.config.js
file
and run npx stylescope --setup device
import { ScopedStyleVitePlugin } from "react-stylescope/dist/lib/vite-loader";
// A possible config may looked like this
export default defineConfig({
plugins: [react(), ScopedStyleVitePlugin()] // Added to the plugin array
});
That is all to configure.
API documentation
getScopedName
Returns a
scoped
name unique to the calling component. The value returned must be stored in a variable namedscoped
. This is a requirement@param
name
A unique name for the component. It may be the name of the component.Do not forget to name your variable
scoped
const App = ()=>{ // Prevent regeneration of new scoped name on re-render const scoped = useMemo(()=>getScopedName('App'),[]); // rest of your code... }
ScopedStyleSheets
A component that renders a style element with your style sheet.
@paramprops.styles
Pass the style sheet to the styles prop
useScopedStyleSheet
Creates a css string from a React CSSProperties object. The style object passed to
useScopedStyleSheet
does not get to the browser. It's transpiled into strings before the code gets served to the browser. The function only returns a pre-computed object when your application runs in the browser.
All dirty works (conversion of the styles object to css string) is done before the code gets to the browser.@param
styleSheet
Styles object.@param
marker
Pass thescoped
variable here. Anything other than the varible namedscoped
won't work.const App = ()=>{ const [ theme, setTheme ] = useState('light') const color = `${theme==='light'?'black':'white'}`; // Prevent regeneration of new scoped name on re-render const scoped = useMemo(()=>getScopedName('App'),[]); // Get keys and style sheet const { keys, sheet } = useScopedStyleSheet({ '.container':{ opacity: 0.9, margin: '10px', // Dynamic values must be set inside template literals color: `${color}` } },scoped) // rest of your code... return ( <div className={keys['.container']}> <h1>Hello world</h1> <ScopedStyleSheet styles={sheet} /> </div> ) }
Setting style values dynamically
In your style objects passed to useScopedStyleSheet
, when setting the values dynamically, do so only in template literals.
The following are wrong ❌ when setting style object values
Rule 1
This is wrong.const styleObject = { /*...*/ }; const {keys, sheet} = useScopedStyleSheet(styleObject,scoped)
Solution: Do not pass the object dynamically. Do it like below;
const {keys, sheet} = useScopedStyleSheet({ /*...*/ },scoped)
Rule 2
This is wrong.const className = '.my-class'; const {keys, sheet} = useScopedStyleSheet({ [className]: { /*...*/ } },scoped)
Solution: Do not set keys dynamically. Do it like below;
const {keys, sheet} = useScopedStyleSheet({ '.my-class': { /*...*/ } },scoped)
Rule 3
This is wrong.const {keys, sheet} = useScopedStyleSheet({ '.my-class': { margin: 10 + 'px' } },scoped)
Solution: Set dynamic values this way instead. Always have the final value stored in a variable and set using template literals.
const margin = 10 + 'px'; const {keys, sheet} = useScopedStyleSheet({ '.my-class': { margin: `${margin}` } },scoped)
Happy Coding!