There are a number of ways to style React components. Choosing the right method for styling components isn’t a perfect absolute. It’s a specific decision that should serve your particular use case, personal preferences, and above all, architectural goals of the way you work.
For example, I make use of notifications in React JS using Noty, and the styling should be able to handle plugins too.
Some of my goals in answering the question included covering these:
- global namespacing
- dependencies
- reusability
- scalability
- dead-code elimination
There seems to be a number of ways of styling React components used widely in the industry for production level work:
- inline CSS
- normal CSS
- CSS in JS libraries
- CSS Modules
- Sass & SCSS
- Less
- Stylable
For each method, I’ll look at the need for dependencies, the difficulty level, and whether or not the approach is really a good one or not.
Inline CSS
- Dependencies: None
- Difficulty: Easy
- Approach: Worst
I don’t think anyone needs an introduction to inline CSS. This is the CSS styling sent to the element directly using the HTML or JSX. You can include a JavaScript object for CSS in React components, although there are a few restrictions such as camel casing any property names which contain a hyphen. You can style React components in two ways using JavaScript objects as shown in the example.
Example
import React from "react";
const spanStyles = {
color: "#fff",
borderColor: "#00f"
};
const Button = props => (
<button style={{
color: "#fff",
borderColor: "#00f"
}}>
<span style={spanStyles}>Button Name</span>
</button>
);
Regular CSS
- Dependencies: None
- Difficulty: Easy
- Approach: Okay
Regular CSS is a common approach, arguably one step better than inline CSS. The styles can be imported to any number of pages and elements unlike inline CSS, which is applied directly to the particular element. Normal CSS has several advantages, such as native browser support (it requires no dependencies), there’s no extra tooling to learn, and there’s no danger of vendor lock in.
You can maintain any number of style sheets, and it can be easier to change or customize styles when needed. But regular CSS might be a major problem if you’re working on a bigger project with lots of people involved, especially without an agreed style guide for writing CSS.
Example
/* styles.css */
a:link {
color: gray;
}
a:visited {
color: green;
}
a:hover {
color: rebeccapurple;
}
a:active {
color: teal;
}
import React from "react";
import "styles.css";
const Footer = () => (
<footer>
© 2020
<a href="https://twitter.com/praveenscience">Find me on Twitter</a>
</footer>
);
export default Footer;
More Information
You can read more about regular CSS usage of the W3C’s Learning CSS page. There are many playgrounds — such as JS Bin, JSFiddle, CodePen, and Repl.it — where you can try it out live and get the results in real time.
CSS-in-JS
CSS-in-JS is a technique which enables you to use JavaScript to style components. When this JavaScript is parsed, CSS is generated (usually as a <style>
element) and attached into the DOM.
There are several benefits to this approach. For example, the generated CSS is scoped by default, meaning that changes to the styles of a component won’t affect anything else outside that component. This helps prevent stylesheets picking up bloat as time goes by; if you delete a component, you automatically delete its CSS.
Another advantage is that you can leverage the power of JavaScript to interact with the CSS. For example, you can create your own helper functions in JavaScript and use them directly in your CSS to modify the code.
Next, we’ll look at two libraries that can be used to implement this in a React app.
JSS
- Dependencies:
react-jss
- Difficulty: Easy
- Approach: Decent
JSS bills itself as “an authoring tool for CSS which allows you to use JavaScript to describe styles in a declarative, conflict-free and reusable way”. It’s framework agnostic, but when it comes to styling React components, React-JSS integrates JSS with React using the new Hooks API.
Example
import React from "react";
import {render} from "react-dom";
import injectSheet from "react-jss";
// Create your styles. Since React-JSS uses the default JSS preset,
// most plugins are available without further configuration needed.
const styles = {
myButton: {
color: "green",
margin: {
// jss-expand gives more readable syntax
top: 5, // jss-default-unit makes this 5px
right: 0,
bottom: 0,
left: "1rem"
},
"& span": {
// jss-nested applies this to a child span
fontWeight: "bold" // jss-camel-case turns this into 'font-weight'
}
},
myLabel: {
fontStyle: "italic"
}
};
// Define the component using these styles and pass it the 'classes' prop.
const Button = ({ classes, children }) => (
<button className={classes.myButton}>
<span className={classes.myLabel}>{children}</span>
</button>
);
// Finally, inject the stylesheet into the component.
const StyledButton = injectSheet(styles)(Button);
const App = () => <StyledButton>Submit</StyledButton>
render(<App />, document.getElementById('root'))
More Information
You can learn more about this approach in the JSS official documentation. There’s also a way to try it out using their REPL (read-eval-print loop).
Styled-Components
- Dependencies:
styled-components
- Difficulty: Medium
- Approach: Decent
Styled-components is a further library that implements the above-mentioned CSS-in-JS technique. It utilizes tagged template literals — which contain actual CSS code between two backticks — to style your components. This is nice, as you can then copy/paste CSS code from another project (or anywhere else on the Web) and have things work. There’s no converting to camel case or to JS object syntax as with some other libraries.
Styled-components also removes the mapping between components and styles. As can be read in their documentation, this means that when you’re defining your styles, you’re actually creating a normal React component that has your styles attached to it. This makes your code more succinct and easy to follow, as you end up working with a <Layout>
component, as opposed to a <div>
with a class name of “layout”.
Props can be used to style styled components in the same way that they are passed to normal React components. Props are used instead of classes in CSS and set the properties dynamically.
Example
import React from "react";
import styled, { css } from "styled-components";
const Button = styled.button`
cursor: pointer;
background: transparent;
font-size: 16px;
border-radius: 3px;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
transition: 0.5s all ease-out;
${props =>
props.primary &&
css`
background-color: white;
color: green;
border-color: green;
`};
`;
export default Button;
More Information
Styled-components has detailed documentation, and the site also provides a live editor where you can try out the code. Get more information on styled-components at styled-components: Basics.
Styled-Components Alternatives
There are a number of other CSS-in-JS libraries to consider depending on your needs. Some popular examples include:
- Emotion is smaller and faster than styled-components. If you already use styled-components, you may not need to rush out and change libraries — its maintainers say it is closing the gap.
- Linaria is a popular option for developers looking to maximize Core Web Vitals scores. Linaria’s core differentiator is that it’s a zero-runtime library — all of your CSS-in-JS is extracted to CSS files during build.
CSS Modules
- Dependencies:
css-loader
- Difficulty: Tough (Uses Loader Configuration)
- Approach: Better
If you’ve ever felt like the CSS global scope problem takes up most of your time when you have to find what a particular style does, or if getting rid of CSS files leaves you nervously wondering if you might break something somewhere else in the code base, I feel you.
CSS Modules solve this problem by making sure that all of the styles for a component are in one single place and apply only to that particular component. This certainly solves the global scope problem of CSS. Their composition feature acts as a weapon to represent shared styles between states in your application. They are similar to mixins in Sass, which makes it possible to combine multiple groups of styles.
Example
import React from "react";
import style from "./panel.css";
const Panel = () => (
<div className={style.panelDefault}>
<div className={style.panelBody}>A Basic Panel</div>
</div>
);
export default Panel;
.panelDefault {
border-color: #ddd;
}
.panelBody {
padding: 15px;
}
Please note that, if you’re using Create React App, it supports CSS Modules out of the box. Otherwise, you’ll need webpack and a couple of loaders that enable webpack to bundle CSS files. Robin Wieruch has a great tutorial on this.
Sass & SCSS
- Dependencies:
node-sass
- Difficulty: Easy
- Approach: Best
Sass claims that it’s the most mature, stable, and powerful professional-grade CSS extension language in the world. It’s a CSS preprocessor, which adds special features such as variables, nested rules and mixins (sometimes referred to as “syntactic sugar”) into regular CSS. The aim is to make the coding process simpler and more efficient. Just like other programming languages, Sass allows the use of variables, nesting, partials, imports and functions, which add super powers to regular CSS.
There are a number of ways that a Sass stylesheet can be exported and used in a React project. As you might expect, Create React App supports Sass out of the box. If you’re using webpack, you’ll need to use the sass-loader, or you could just use the sass --watch
command.
We look at how to use Sass with Create React App at the end of this article.
Example
$font-stack: 'Open Sans', sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
More Information
Learn more about using and installing Sass with a variety of programming languages from their official documentation at Sass: Syntactically Awesome Style Sheets. If you want to try something out, there’s a service called SassMeister – The Sass Playground! where you can play around with different features of Sass and SCSS.
Less
- Dependencies:
less
,less-loader
- Difficulty: Easy
- Approach: Good
Less (Leaner Style Sheets) is an open-source, dynamic preprocessor style sheet language that can be compiled into CSS and run on the client side or server side. It takes inspiration from both CSS and Sass and is similar to SCSS. A few notable differences include variables starting with an @
sign in Less and with a $
in Sass.
Example
@pale-green-color: #4D926F;
#header {
color: @pale-green-color;
}
h2 {
color: @pale-green-color;
}
More Information
You can get started with Less from the official documentation, and there’s LESSTESTER, a Less Sandbox that converts your Less code into CSS.
Stylable
- Dependencies:
stylable
,@stylable/webpack-plugin
- Difficulty: Difficult
- Approach: Better
If you’re not the biggest fan of CSS-in-JS, then Stylable might be for you. It’s a preprocessor that enables you to scope styles to components so they don’t leak and clash with other styles elsewhere in your app. It comes with several handy features — such as the ability to define custom pseudo-classes — so that you can apply styles to your components based on state. It is also inspired by TypeScript, with the project’s home page stating:
We want to give CSS a type system — to do for CSS what TypeScript does for JavaScript.
When it comes to integrating Stylable with React, they offer a handy guide. There’s also the create-stylable-app project, which will initialize a React-based web application with Stylable as its styling solution.
Example
@namespace "Example1";
/* Every Stylable stylesheet has a reserved class called root
that matches the root node of the component. */
.root {
-st-states: toggled, loading;
}
.root:toggled { color: red; }
.root:loading { color: green; }
.root:loading:toggled { color: blue; }
/* CSS output*/
.Example1__root.Example1--toggled { color: red; }
.Example1__root.Example1--loading { color: green; }
.Example1__root.Example1--loading.Example1--toggled { color: blue; }
More Information
Stylable has much more to offer. The official documentation on getting started provides detailed explanation.
Getting Our Hands Dirty
With so many options available, I got my hands dirty and tried them one by one. Thanks to Git, I was able to version control and compare everything to see which option is the winner. I was able to get some clarity on how many dependencies I was using and how my workflow was while working with complex styles. I had a bit of a struggle with everything other than normal CSS, CSS Modules and SCSS.
Office Work
CSS Modules helps with imports and other things, but when I tried using it, there wasn’t much support for extending it. CSS Modules had issues when I was using multiple CSS classes and hierarchies. The only good thing about it is that you don’t get any CSS conflicts, but the drawback is that your CSS code is extremely huge. It’s a bit like the BEM methodology.
Added to this, dealing with pseudo elements and states was hell. At times, CSS Modules wouldn’t even compile when I tried to import the contents of another class from a different file. I would prefer to use mixins in SCSS for this, but unfortunately, CSS Modules is still very basic in this area. The composes
keyword here almost never worked for me. This is a huge drawback that I personally faced. It could be just my fault for not using it correctly, but it didn’t work for even a genuine case.
Personal Project
I used SCSS as my next attempt in working with styles for React. Fortunately, it worked. Comparing SCSS with CSS Modules gave me good insight. There are so many things that are common between them. One catch here is that I have already used SCSS, and I’m very much comfortable with it, as it’s similar to CSS, but with superpowers. The only thing I need to do along with using Create React App is to install one more dependency, node-sass
, and nothing else. No touching webpack configs or ejecting the React JS application from Create React App.
Looking at the power of CSS Modules, I made a shallow comparison between SCSS and CSS Modules and found that I have most features in SCSS. Talking about composing — which is the main reason why my team chose CSS Modules — we can use @mixin
and @include
in SCSS and they work really well. I haven’t seen CSS modules interacting with the JavaScript, so it’s the same with SCSS — no interaction with the JavaScript part. Looping and inclusions with functions are unique to SCSS, so I thought of going ahead with SCSS for my personal project and a new project in my office.
And the Winner is…
Clearly, SCSS is the absolute winner here. SCSS provides a lot of new features out of the box when compared to CSS Modules. Now follows an in-depth analysis of SCSS — how it’s better and why you should use SCSS in your next project.
SCSS Wins: In-depth Analysis
I love SCSS because of the features it offers. The first thing is that it’s very similar to CSS. You don’t need to learn something new to understand SCSS. If you know CSS, you probably know Sass. Sass comes with two different syntaxes: Sass itself and SCSS, which is used more. SCSS syntax is CSS compatible, so you just have to rename your .css
file to .scss
. Of course, by doing this you aren’t using any of the superpowers and abilities Sass provides, but at least you realize you don’t need to spend hours and hours to start using Sass. From this starting point, you’d be able to learn the Sass syntax as you go.
You can head over to Sass Basics to get up and running with the basics. Setting up Sass support for your project and starting to style using SCSS is straightforward in the case of React. The next advantage in using SCSS, as with any CSS pre-processor, is the ability to use variables. A variable allows you to store a value or a set of values, and to reuse these variables throughout your Sass files as many times you want and wherever you want. Easy, powerful, and useful. This helps with theming your product or application and getting it styled according to the customer needs without doing much, other than switching a few bits of code, here and there.
Nesting in CSS (or SCSS) is one of the best things that Sass can offer. Sass allows you to use a nested syntax, which is code contained within another piece of code that performs a wider function. In Sass, nesting allows a cleaner way of targeting elements. In other words, you can nest your HTML elements by using CSS selectors. There are so many benefits of nesting the code with Sass, with the main one being the maintainability and readability of SCSS. We’ve all heard of the DRY concept in code, but in CSS, this prevents the need to rewrite selectors multiple times. This also helps in maintaining the code more easily.
The ability to use partials is great. You can split SCSS into partials anywhere and include them wherever they’re required. You can also have them split into mixins and pass some parameters to provide a different CSS altogether. Using variables is great, but what if you have blocks of code repeating in your style sheet? That’s when mixins come into play. Mixins are like functions in other programming languages. They return a value or set of values and can take parameters including default values. Note that Sass also has functions, so don’t confuse a mixin with a function.
Using SCSS with React
With the upgraded Create React App released recently, we got a lot of new tools to play with. Sass is one that I’m excited to have built in, since we used to have to make .scss
files compile and write to .css
files right in our folder structure. You may be concerned about using Sass in React. Isn’t it a smarter way to write styles with CSS-in-JS libraries like styled-components or aphrodite? I believe that adding Sass support to Create React App will be a big help for React beginners.
Here are some steps to follow:
- Let’s start by installing the Create React App. You can do that by running
npm install -g create-react-app
globally or usingnpx create-react-app
to download and invoke it immediately so your installed package won’t be anywhere in your globals. You can find out more about npx here. - Create a new React project with
create-react-app <app-name>
and then change into that directory. - Install the
node-sass
dependency usingnpm install node-sass --save
. This will compile yourscss
tocss
. - That’s it — we’re done. We can test the configuration by changing our
src/App.css
file tosrc/App.scss
file and updatingsrc/App.js
to import it. Then we can try out some cool Sass/SCSS features.
Common Examples
Here’s a way to use variables in SCSS:
$blue: #004BB4;
$ubuntu-font: 'Ubuntu', 'Arial', 'Helvetica', sans-serif;
$nunito-font: 'Nunito', 'Arial', 'Helvetica', sans-serif;
Once you’ve created the variables, you can use them wherever you need to, like this:
h1 {
font: $ubuntu-font;
color: $blue;
}
a {
font: $nunito-font;
background-color: $blue;
padding: 6px;
}
When you compile your SCSS files, the Sass compiler will take care of the variables you’ve used in your source file, replacing the variable name with its stored value. And changing the value of the color is as quick as updating the variable content and re-compiling. Gone are the days of using “Find and Replace” in your favorite text editor to change colors in your CSS file.
A worthwhile feature that I covered previously is the “nesting” feature of SCSS. An example of that can be demonstrated here:
<ul class="navbar">
<li><a href="/">Item <span>1</span></a></li>
<li><a href="/">Item <span>2</span></a></li>
<li><a href="/">Item <span>3</span></a></li>
<li><a href="/">Item <span>4</span></a></li>
<li><a href="/">Item <span>5</span></a></li>
</ul>
.navbar {
font: $ubuntu-font;
color: $blue;
li {
margin-left: 1rem;
a {
padding: 5px;
font-size: 1.5rem;
span {
font-weight: 600;
}
}
}
}
However, be aware that nesting too deeply is not good practice. The deeper you nest, the more verbose the Sass file becomes and the larger the compiled CSS will potentially be, since the nesting is flattened when compiled. So, overuse of nesting can create overly specific CSS rules that are hard to maintain. There’s a chance that the selectors can’t be reused, and there are performance issues too. Nested selectors will create a long CSS selector string that will end up generating a bigger CSS file.
Wrapping Up
In this article, I looked at several ways of styling components in a React application. I then compared and contrasted these methods examining their advantages and disadvantages. Finally, I demonstrated how to use Sass (my preferred method of styling a React application) in a Create React App project.
Sass is a CSS preprocessor, and CSS preprocessors are here to stay. They extend the basic CSS features by providing you with a set of powerful functionalities that will raise your productivity right away. I mentioned a few benefits, but there are many more, like inheritance, functions, control directives, and expressions like if()
, for()
or while()
, data types, interpolation, and so on.
Becoming a Sass guru may take a bit of time; all you need to do is look into the Bootstrap Sass files to see how Sass could turn into a complex thing. But learning the basics and setting it up for your project is something you could start today.
FAQs About Styling React Components
React components can be styled using various methods, including inline styles, CSS stylesheets, CSS modules, CSS-in-JS libraries (e.g., styled-components, Emotion), and utility-first CSS frameworks (e.g., Tailwind CSS).
nline styles use JavaScript objects to define styles directly in your component, while external stylesheets use separate .css files. Inline styles can make components more self-contained, while external stylesheets promote separation of concerns.
CSS modules are a way to locally scope CSS styles to a specific component. They work by automatically generating unique class names for each component, preventing style conflicts in your application.
CSS-in-JS libraries, like styled-components and Emotion, allow you to write CSS styles directly in your JavaScript code using template literals. They offer dynamic and scoped styling, making it easier to manage component-specific styles.
Conditional styles in React can be applied by using JavaScript expressions within your style definitions or by toggling class names based on conditions in your component’s JSX.
Using a CSS framework like Bootstrap with React is common and can help speed up development. However, it’s important to be mindful of potential conflicts and customize the framework’s styles to match your application’s design.
Utility-first CSS frameworks like Tailwind CSS provide a set of pre-defined utility classes that you can apply directly to your components. They promote consistency and can reduce the need to write custom CSS.
You can pass props to styles in various ways, such as conditional rendering of style properties based on props, using template literals with CSS-in-JS libraries, or creating utility classes that depend on component props.
To optimize performance, use techniques like memoization (e.g., React’s useMemo
) for styles that don’t change frequently, and consider minimizing re-renders by using libraries like shouldComponentUpdate
or React’s memo
for functional components.
SS preprocessors like Sass and Less provide advanced features for writing styles. They can be integrated with React by configuring build tools (e.g., Webpack) to process Sass or Less files into regular CSS during the build process.
![Praveen Kumar](https://uploads.sitepoint.com/wp-content/uploads/2019/09/1567562071praveen-150x150.jpeg)
Praveen is a software and web developer, cloud computing consultant, full-stack developer, UX architect, a CEO, and even … a cook. You can find him at praveen.science.