CSS Architecture with ReactJS

CSS Architecture with ReactJS

We are living in a new today, every day, filled with new tools and paradigms.

We often catch ourselves trying to apply yesterday’s architectures to new technologies, which can end badly.

One of these cases is BEM – a CSS naming convention – which solves a problem that we maybe don’t have anymore.

But first things first.

What is BEM?

BEM is a naming convention for CSS with a simple and direct philosophy: code consistency, scalability, and reusability.

The methodology is based on its name: Block-Element-Modifier. This means that your classes will be split between three entities, with one with a different objective and role in your architecture and code organization:

  • Block: Independent logical and functional components.
  • Element: A part of a block that has no standalone meaning.
  • Modifier: Define the behavior and the appearance of a block or element.

When talking about selectors with BEM we have three little rules:

  • Only use CSS classes.
  • Class names can contain numbers and should not contain special characters.
  • Individual words are separated by a hyphen.

BEM entities should look like this:

/* The name of the block, which is also the namespace of its elements and modifiers.*/
<b>.block
</b>
/* The block namespace followed by a double underscore and the element name. */
<b>.block__element
</b>
/* The block or element namespace followed by a double hyphen and the modifier name. */
<b>.block--modifier, .block__element--modifier</b>
Code language: CSS (css)

Why should I use it?

The BEM philosophy was created based on a few premises: code consistency, scalability, reusability, productivity, and teamwork. With that in mind is good to say that BEM is already adopted by many developers around the globe and big companies such as Google and Twitter.

If you wanna learn more about this methodology, check this article about CSS Architectures.

Powering Up

When it comes to naming convention and organization, BEM rocks. It’s simple and functional.

Still, when we talk about CSS Architectures there’s another point we should care about: folder structure. And that’s when we mix one more architecture into the recipe: ITCSS.

ITCSS is a methodology introduced by Harry Roberts to help create, manage, and scale large CSS projects. In his own words:

This is a methodology that involves visualising your entire CSS project as a layered, upside-down triangle. This hierarchical shape represents a model that will help you order your CSS in the most effective, least wasteful way.

I won’t dig deep into this methodology but I recommend reading Harry’s post to get the concepts behind it.

In a few words it proposes organizing the code in layers, structured as an inverted triangle, where we start with the most generic elements on the top, and finish with the most specific elements on the bottom.

The key point here is that we can use the layers as an effective folder structure to organize our code. On my previous experiences, I used this methodology a little bit different than its original proposal, having the code set up on these layers:

  • Settings: Basic configurations and variables.
  • Tools: Functions and mixins.
  • Base: Basic styles that will be applied to every page. It’s a good place to put reset/normalize code.
  • Components: UI chunks that compose the interface.
  • Utilities: Very specific rules, it’s the only layer that you can use !important.

Now everything we need is to mix these two methodologies and we’ll end up with a powerful and yet simple CSS architecture in our hands.

BEM CSS Project Structure

A ReactJS Approach

The BEM+ITCSS architecture was all we needed in the past years until everything changed. ReactJS became one of the main SPA libraries, in which the way of thinking in components is kinda different than before.

Now, every component is a JS module where the HTML structure is totally related to it and you can dynamically change your component states and variations via its custom properties. You don’t only link style tags to a semantic HTML structure anymore, you now have the power to create totally logical, dynamic, and functional components.

So how do we approach our styles and code organization in this new scenario?

Keep our style isolated from our React components, using the BEM+ITCSS methodology, or change radically with a CSS-in-JS approach?

I would suggest staying somewhere in between and using the advantages of our previous knowledge.

The Think-Adapt- First Approach

The idea of using these methodologies and naming conventions started with a few reasons in mind: keeping styles isolated, creating unique selectors, and clarifying the relationship between selectors within a component scope.

No one uses BEM conventions because they like to type double underlines or double hyphens, but it definitely helps with code consistency, scalability, reuse, productivity, and predictability. Those are all viable premises, so why not keep using them?

Because we can’t. The project architecture changed when we decided to introduce React in the equation. With that, a few restrictions, patterns, and new possibilities appeared.

This is a perfect time to adapt our previous rules to this new context. And here’s another lib I strongly recommend including in your toolbelt.

CSS Modules

To explain all the advantages and functionalities of CSS Modules, I’d rather use the words of its creator, Glen Maddern.

The overall idea here – besides thousands of benefits you get from it – is CSS local scopes. Now, all React components can be totally isolated in a logical and presentational state. This is how the structure looks like:

└── button
 ├── index.js
 └── styles.css
Code language: CSS (css)

There’s no need to remain with the classic BEM convention inside styles.css. There, we should use the first entity as the component namespace, but now with CSS Modules, this relationship is dynamically created based on the JS component name. Behind the scenes it work this way:

/*
* Reset
*/
.button {
  appearance: none;
  border: 0;
  background-color: white;
  cursor: pointer;
  color: #333;
  font-size: .9rem;
  font-weight: bold;
}
.button:focus,
.button:focus:hover {
  border-color: #51a7e8;
  box-shadow: 0 0 5px rgba(81, 167, 232, .5);
  outline: 0;
}
/*
* Sizes
*/
.small {
  padding: .5em 1.4em;
}
.medium {
  padding: .8em 1.4em;
}
.large {
  padding: 1.2em 2.2em;
}
/*
* Themes
*/
.default {
  border: 1px solid #ddd;
  border-radius: 3px;
  background: linear-gradient(to bottom, #fefefe 0%, #ddd 100%);
}
.default:hover {
  border-color: #bbb;
  background: #ddd;
}
.default:active {
  border-color: #aaa;
  background: linear-gradient(to bottom, #bbb 0%, #ddd 44%);
}
Code language: CSS (css)

And inside of your component, you just include the classes you need depending on its rules. Our button example can be described this way:

import PropTypes from 'prop-types'
import React from 'react'
import styles from './styles.css'

export const ButtonType = {
  BUTTON: 'button',
  RESET: 'reset',
  SUBMIT: 'submit',
}
export const ButtonTheme = {
  DEFAULT: 'default',
  POSITIVE: 'positive',
  DANGER: 'danger',
}
export const ButtonSize = {
  SMALL: 'small',
  MEDIUM: 'medium',
  LARGE: 'large',
}

const Button = ({ type, onClick, children, theme, size }) => {
  const className = `${styles.button} ${styles[theme]} ${styles[size]}`
  return (<button type="{type}">{children}</button>)
}
Button.propTypes = {
  type: PropTypes.oneOf(Object.keys(ButtonType)),
  theme: PropTypes.oneOf(Object.keys(ButtonTheme)),
  size: PropTypes.oneOf(Object.keys(ButtonSize)),
  onClick: PropTypes.func.isRequired,
  children: PropTypes.node.isRequired,
}
Button.defaultProps = {
  type: ButtonType.BUTTON,
  theme: ButtonTheme.DEFAULT,
  size: ButtonSize.MEDIUM,
}
export default Button
Code language: CSS (css)

Ok. Now we have the solution for the components’ layer.

What about global styles, such as settings, normalizes and resets?

ITCSS Revival

The layered folder structure based on ITCSS still fits perfectly with our needs, so why not continue using it?

The idea is to create the same styles folder inside our src project, except the components folder, because they are already defined by the React default project layout.

Now, we have something like that:

ITCSS with ReactJS Project

Using the :global tag, we can import the style file inside your main application making your styles available globally as a normal class.

Again, the Think-Adapt-First

The idea behind this organization is to help you create better ReactJS projects by keeping your CSS architecture in a way that you can scale and keep it sustainable, even with thousands of components and developers working on it.

However, the real point here is to open your mind and give you the idea of adaptation!

Sometimes it’s hard to adapt because you gotta let go of things that were hard to master, but don’t forget that the problems you solved may not even exist anymore.

So, young pilgrims, keep searching for knowledge.

Sources and extra reading material:

About the author.

Douglas da Silva
Douglas da Silva

Also known as Doug Gimli, I'm a developer that works with interactive solutions facing web projects, trying every day to deliver a full and great experience to users.