8 Ways to Style React Components Compared

I’ve been working with a couple of developers in my office on React JS projects, who have varied levels of React JS experience. We’ve been solving some crazy problems like handling the weird way Redux does state initialization and making an axios request payload work with PHP and understanding what goes on in the background. This article arose out of a question about how to style React components.

The Various Styling Approaches

There are various 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 about eight different ways of styling React JS components used widely in the industry for production level work:

  • Inline CSS
  • Normal CSS
  • CSS in JS
  • Styled Components
  • 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. There are a few restrictions like replacing every - with camelCase text. You can style them 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 decreasing the file size with a clean code structure.

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 pattern to do styling in CSS.

Example

a:link {
  color: gray;
}
a:visited {
  color: green;
}
a:hover {
  color: rebeccapurple;
}
a:active {
  color: teal;
}

More Information

You can read more about regular CSS usage of the W3C’s Learning CSS page. There are many playgrounds like JS Bin – Collaborative JavaScript Debugging, JSFiddle, CodePen: Build, Test, and Discover Front-end Code, Repl.it – The world’s leading online coding platform, etc. where you can try them out live and get the results in real time.

CSS in JS

  • Dependencies: jss, jss-preset-default, jss-cli
  • Difficulty: Easy
  • Approach: Decent

CSS in JS is an authoring tool for CSS which allows you to use JavaScript to describe styles in a declarative, conflict-free and reusable way. It can compile in the browser, on the server side or at build time in Node. It uses JavaScript as a language to describe styles in a declarative and maintainable way. It’s a high performance JS-to-CSS compiler which works at runtime and server-side. When thinking in components, you no longer have to maintain a bunch of style sheets. CSS-in-JS abstracts the CSS model to the component level, rather than the document level (modularity).

Example

import React from "react";
import injectSheet from "react-jss";

// Create your Styles. Remember, since React-JSS uses the default 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"
  }
};

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);

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 an example of the above-mentioned CSS in JS. It basically gives us CSS with other properties you wish we had in CSS like nesting. It also allows us to style the CSS under the variable created in JavaScript. You could normally create a React component along with the styles attached to it without having to create a separate file for CSS. Styled-components allows us to create custom reusable components which can be less of a hassle to maintain. Props can be used in styling the components in the same way it is passed in the 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 a 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.

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 you’ve had to write a CSS file without organizing it properly to make the code work first, or if getting rid of the files gives you a slight nudge in your heart wondering if you might break the whole code, I feel you. CSS Modules make sure that all of the styles for a component are at one single place and apply to that particular component. This certainly solves the global scope problem of CSS. The composition feature acts as a weapon to represent shared styles between the states. It’s similar to the mixin in Sass, making 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;
}

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.

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 a 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/core, @stylable/runtime, @stylable/optimizer, @stylable/module-utils, @stylable/custom-valu
  • Difficulty: Difficult
  • Approach: Better

Stylable is another pre-processor joining Sass, SCSS, and Less. If there is a struggle in getting handy with styled components — as their syntax is slightly different from Normal CSS — this comes to the rescue. Stylable is just like CSS but offers more opportunities to make each component discreet. This can do what CSS Modules finds it harder to do, which is styling the internal parts of a UI. Along with the other properties of CSS, Stylable also offers custom pseudo classes and pseudo elements. This property of Stylable automatically allows us to create custom CSS classes, which enables us to do the styling to internal parts of the components.

Example

@namespace "Page";
:import {
    -st-from: './video-player.st.css';
    -st-default: VideoPlayer;
}
.mainVideo {
    -st-extends: VideoPlayer; /* define mainVideo as VideoPlayer */
}
.mainVideo::playButton { /* override mainVideo playButton */
    background: green;
    color: purple;
}
/* CSS output*/
.Page__mainVideo.VideoPlayer__root {}
.Page__mainVideo.VideoPlayer__root .VideoPlayer__playButton {
    background: green;
    color: purple;
}

More Information

Stylable has much more to offer. The official documentation on getting started provides detailed explanation. There’s separate documentation on React integration to manually integrate Stylable with a React component.

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 will not even compile when I try to import the contents of another class from a different file. I would prefer using mixins in SCSS for this, but unfortunately, CSS Modules is still very basic in this area. The composes keyword here almost never works 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 am very much comfortable with it as it is similar to CSS, but with super-powers. The only thing I need to do along with Create React App is that I just need to install one more dependency, node-sass and nothing else. No touching webpack configs or ejecting the React JS application from CRA.

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.

The Powerful One?

Clearly, SCSS is the absolute winner here. SCSS provides a lot of new features out of the box when compared to CSS Modules. I am going to make an in-depth analysis of SCSS, how it is 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 is extremely 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 are not 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 would 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 as per 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 thing 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 anywhere into partials and include them anywhere 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 stylesheet? That is 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 do not confuse a mixin with a function.

Using SCSS with React JS

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 .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 to beginners of React. How do I use Sass in React is one of the questions I always hear from people getting into React. With the React 16.6 additions like React.memo() and the React 16.7 functional additions like hooks, starting with React will be easier than ever!

  1. Install the Starter App using Create React App

    Let’s start by installing the starter app. You can do that by running npm install -g create-react-app globally or using npx create-react-app to install and invoke it immediately so your installed package won’t be anywhere in your globals. Check out more about npx.

  2. Install node-sass dependency

    Let’s run npm install node-sass to install node-sass to help in compiling your scss to css.

  3. That’s it — we’re done. We can test the configuration by changing our index.css file to index.scss file and trying 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 have 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

CSS pre-processors 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. We mentioned a few benefits but there are many more, like inheritance, functions, control directives, and expressions like if(), for() or while(), data types, interpolation, etc. 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 won’t take you long.

Try this out and let me know if you need any support in setting this up. I am just a message away.