When I started developing React applications, I didn't pay enough attention to the styling part.
For some reason, I didn't think it's that much important. Especially when there is also an option to pick some sort of UI library.
But as I learned along the way, picking the right styling approach is crucial for the success of your project.
Later on, I started using CSS styling. And I started to learn how to use it properly with React.
info
React official documentation doesn't tell us a lot about the styling part. That being said, it's upon us to do our due diligence, and pick the right styling approach for our React application.
What immediately caught my attention, is the concept of CSS scoping. And I decided to write an article about CSS scopes, so you can learn it too. So without any further ado, let's start by explaining what CSS scope is in React.
What Is CSS Scope in React?
In React application, the scope is a part of a DOM tree that CSS can affect.
note
Scoped CSS lets you target a specific DOM element along with its children, without affecting any other elements in the component tree.
info
If you want to learn more about DOM, and what's the difference between real DOM and virtual DOM, you're in luck. Wo wrote an article covering this topic. You can read the full article here.
Let's examine how CSS scopes work in React, by looking at the example below.
We have 2 components using the same className
. They also have 2 separate stylesheets.
Example of component structure
components
├── ComponentA.jsx
├── componentA.css
├── ComponentB.jsx
└── componentB.css
For the components, they are looking exactly the same. The only difference is the import of stylesheets.
ComponentA.jsx
import "./componentA.css";
const ComponentA = () => {
return <div className="container">Component A</div>;
};
export default ComponentA;
ComponentB.jsx
import "./componentB.css";
const ComponentB = () => {
return <div className="container">Component B</div>;
};
export default ComponentB;
Stylesheets are also very similar, the only difference is the background-color
.
componentA.css
.container {
margin: 16px 0;
background-color: lime;
border-radius: 8px;
padding: 80px;
}
componentB.css
.container {
margin: 16px 0;
background-color: rebeccapurple;
border-radius: 8px;
padding: 80px;
}
If you thought that component will have different color, you're wrong! And it all has to do with CSS scopes in React.
note
By default, all CSS rules are scoped globally for the entire React application. This means that using the same className
for 2 components will cause a collision.
This is what our 2 components will look like. They have the same background color, because of the collision in className
.
As you can see from the previous example, we can't use the same className
for 2 components. At least not with default React configuration.
Luckily for us, this problem can be solved by modifying the configuration of a bundler.
tip
In React application, we can change CSS scopes by modifying the configuration.
Is CSS Scoped in React?
Before we dive deeper into scoping CSS in React, Let's see how CSS scopes work in React by default.
By default, CSS in React is scoped globally. This means that using the same className for 2 elements will cause a clash.
One way to avoid clashes without any additional configuration is to make sure you're using unique class names for every component.
However, this approach is not bulletproof. Using this approach, you always have to check if the class name is not already being used.
If that's something you're not interested in, let's look at different options in the next section.
Different Ways to Scope CSS in React
In React, everything is component-based. Wouldn't be ideal if we can also scope styling to a particular component? This way, we can just focus on writing CSS. And we don't have to worry about CSS clashes at all.
Well, I have good news for you! We can do that, and we have multiple options on how to achieve it.
To scope CSS to a component in React, we can:
- Use inline styling
- Use CSS modules
- Use 3rd party libraries
We'll discuss how to achieve component-based scoping with each of them.
Using Inline Styling
The inline styling is an option available for any React project. The good thing about it is that it doesn't require any configuration.
And since it's inline, there is no way that 2 styles can class together.
You can implement inline styling like in the example below.
Adding inline styling
const styles = {
color: "white",
backgroundColor: "black",
display: "block"
};
const App = () => {
return <div style={styles}>Example Component</div>;
};
export default App;
The biggest downside of this approach is that you can't use the full power of CSS styling. On top of that, CSS classes are generally more performant than inline styles.
caution
When using inline styling, you don't have access to all CSS features, like pseudo-classes, pseudo-elements, etc.
Using CSS Modules
If you're using Create React App, you can make use of CSS modules to scope CSS to a certain component.
note
CSS modules are preconfigured by default, so you can start using them right away. if you're using Create React App.
CSS Modules allows the scoping of CSS by automatically creating a unique classname of the format
[filename]\_[classname]\_\_[hash]
. (source: React)
If you want to use CSS as a module, you need to follow the exact format of naming. All CSS module files should have the following format.
[name].module.css
With that being said, let's implement an example component using CSS modules.
First, let's define the CSS module.
.container {
background-color: white;
color: lime;
text-align: center;
}
Now, use it in a component.
import styles from "./example.module.css";
const Example = () => {
return <div className={styles.container}>Example Component</div>;
};
export default Example;
Using CSS modules, we can write CSS without any difference. The only thing that's different is the way we import the module and the way we assign class names.
Using Scoped CSS
Another option to scope CSS to a component is by using a package called React Scoped CSS.
Component with imported scoped CSS file has a unique
data-v-hash
attribute. The CSS selector also has a corresponding hash. So all the styles in the component to the given component. (source: Scoped CSS)
Using this package, you can write CSS as you would do.
example.scoped.css
.example {
background: black;
}
p {
color: white;
}
And then import it in React component.
Example.jsx
import './example.scoped.css'
const Example = () => {
return (
<h1 className="example">
<p>Example component</p>
</h1>
)
}
export default Example
If you're using Create React APP, you can add this package by first setting up Craco.
tip
Follow this guide to set up Craco with Create React App.
When you have craco
configured properly, install craco-plugin-scoped-css
.
npm install --save craco-plugin-scoped-css
# or
yarn add craco-plugin-scoped-css
After that, create craco.config.js
in your project root directory.
module.exports = {
plugins: [
{
plugin: require('craco-plugin-scoped-css'),
},
],
}
note
If you're not using create-react-app
, you can follow this guide to add this package with a manual setup.
Concluding Thoughts
A good understanding of CSS scopes in React can save you a lot of time and trouble.
Debugging CSS is hard enough on its own. And when scopes are introduced, they just make the whole process harder.
By reading this article, you learned what CSS scopes are, and how do they work in React. On top of that, you learned multiple ways to achieve component scoped styling in React.
With all this information in mind, you can start scoping CSS in your React project like a pro!