CSS Architecture with ReactJS
Development Design

CSS Architecture with ReactJS

We are living a new today, every day, filled with new tools and paradigms. Often, we catch ourselves trying to apply yesterday architectures on new technologies, and that can end bad. 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, which one with a different objective and role in your architecture and code organization:

  • Block: Independent logically and functionally 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.*/
.block

/* The block namespace followed by a double underscore and the element name. */
.block__element

/* The block or element namespace followed by a double hyphen and the modifier name. */
.block--modifier, .block__element--modifier

Why should I use it?

The BEM philosophy was created based on a few premises: code consistency, scalability, reusability, productivity and teamwork. With that 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 to the recipe: ITCSS.

ITCSS is a methodology introduced by Harry Roberts to help creating, managing and scaling 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 on 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 use 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 it?

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 to 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

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

And inside of your component you just include the classes you need depending on the 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.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

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 in our needs, so why not remain 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 helping 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 it go from things that were hard to master, but don’t forget that the problems you solved may not even exist anymore.

So, young pilgrims, keeping searching for the knowledge.

 

Sources and extra reading material:

ITCSS – Scalable Maintainable CSS Architecture
BEMIT Naming Convention
ITCSS – Manage Large CSS Projects
GETBEM
How To Use CSS Modules With CreateReactApp
CSS Modules

Need a team for your projects?
We'd love to hear your ideas!

Connect with us!