Photo taken by Amador Loureiro and available on Unsplash.com

React Components & B.E.M. 💍

Recently at CrowdRiff we’ve decided to adopt the BEM naming structure to help organize our ever-scaling web app. As we have started adding more and more features to our app, it became clear that name spacing our element’s classes was an important issue we should catch early.

💁 Super BEM Basics

BEM stands for block, element, modifier. It doesn’t insist on strict rules, and like any class naming convention should be done a way that feels natural. Let’s take a look;

<div class="gallery">
<div class="gallery__imageContainer">
<img class="gallery__image" src="yep.jpg" />
<!-- OR -->
<img class="imageContainer__image" src="yep.jpg"/>
</div>
</div>

A very important principle of BEM is that every element should receive a class. Because every element has a class, when it comes to styling you will only ever need to use class names to select elements. Because you’re only using classnames to select elements, you maintain a similar level of specificity throughout the entire project and won’t run into conflicts — all that matters is the cascade.

Architectural Unity 🏗

Part of the architecture that we follow at CrowdRiff focuses on organizing our folder structure by features. This is a fairly common method in react development, that really support a scaling app.

The components and containers associated with that feature all remain coupled together in the same folder. We use SCSS modules with our structure to keep all of our relational code in the same place.

BEMing a Component 💅

It’s easy to name things semantically without a specific convention to follow, but after some time you will start having ‘container’ classes across multiple components that might need to have all different styling. You will begin running into conflicts with styling because multiple components have the same class name. You can solve this with overly specific CSS declarations, but that may run into a lot of styling problems that rely on specific relationships.

Instead, let’s make an example of what an input component might look like;

export default function InputContainer(props) {
const containerClass = classNames('inputContainer', props.className);
return (
<div className={containerClass}>
<label for={props.id} className="inputContainer__label">
{props.label}
</label>
<input id={props.id} className="inputContainer__input" />
</div>
);
}

This is a really simple component, but it shows the basic idea of BEM in react. Because we will be using this component over and over again, we will be able to target the classes reliable. If we want to create another <input /> in a separate component, it will be name-spaced with its parent’s name.

The Modifier Part 🛠

At CrowdRiff we make heavy use of the fantastic classnames JS utility. If you aren’t familiar with using it, I strongly recommend a read through the docs. In short, it allows you to pass in an object literal where the key is the name of the class desired, and the value a boolean value. When the boolean is true, the class is shown. This makes state-based element class names really flexible and a dream to work with/maintain. Adding these modifiers to elements the BEM way isn’t that different than before…

export default function InputContainer(props) {
  const containerClass = classNames('inputContainer', props.className);
  const inputClass = classNames('inputContainer__input', {
'inputContainer__input--error': props.errors,
'inputContainer__input--isRequired': props.isRequired,
});
return (
<div className={containerClass}>
<label for={props.id} className="inputContainer__label">
{props.label}
</label>
<input id={props.id} className={inputClass} isRequired={props.isRequired} />
</div>
);
}

Above I make use of the classnames utility in two places in this component. Now, I agree that this doesn’t create the most pretty class names, but they are very semantic and readable for an entire team.

The SCSS Part of it All

I think where BEM and its benefits really starts to click is when people start writing SCSS for BEM components. I won’t wax too much about the cool parts, but I have written a few blog posts on this naming convention works well with SCSS and a few handy tricks one can use with SCSS and BEM.

Let’s take a look at what the SCSS might look for this input component…

.inputContainer {
margin: 0.8rem 0;
display: flex;
justify-content: column;
  &__label {
margin-bottom: 0.8rem;
color: black;
opacity: 0.78;
font-size: 12px;

&--large {
font-size: 20px;
}
  }
  &__input {
padding: 8px;
font-size: 16px;
color: black;
opacity: 0.87;
border: 1px solid black;
border-radius: 3px;
    &--green {
color:green;
}
    &:focus {
outline: none;
border: 1px solid tomato;
}
}
}

One of the bonuses to BEM in SCSS it provides the visual benefit of nesting, without the complication that nesting can bring with specificity. Our use of the ‘&’ selector allows us to create a really flat structure. The above code compiles into this…

.inputContainer {
margin: 0.8rem 0;
display: flex;
justify-content: column;
}
.inputContainer__label {
margin-bottom: 0.8rem;
color: black;
opacity: 0.78;
font-size: 12px;
}
.inputContainer__label--large {
font-size: 20px;
}
.inputContainer__input {
padding: 8px;
font-size: 16px;
color: black;
opacity: 0.87;
border: 1px solid black;
border-radius: 3px;
}
.inputContainer__input--green {
color: green;
}
.inputContainer__input:focus {
outline: none;
border: 1px solid tomato;
}

You can see that the structure is extremely flat, without child selectors.

Utility Classes Though?

We decided to not always rely on the BEM modifier structure at CrowdRiff. In some cases it can be cumbersome and not always as flexible. If you want to make the text red, adding the class ‘red’ to it may just be the best answer. I think that this is an okay exception to the BEM principle, because it won’t create problems with specificity or duplication. This utility class will always make something red.

Note — the use of utility classes does result in more nested SCSS and less flat compiled css.

Our solution was to introduce SUIT’s naming convention approach to utility classes, which is to prefix the style with a ‘u-’, like so…

<p class="descriptionContainer__text u-red" >HUH?</p>

I think that the above is a nice compromise for utility functions vs BEM modifiers, and does well when paired with the classnames utility function. Just remember that you need to write your SCSS accordingly though, to make it a truly flexible component an accept all the utility styles, example;

export default function Description(props) {
const textClasses = classNames('descriptionContainer__text', props.className, {
'u-red': props.error
});
return (
<div className="descriptionContainer">
<p for={props.id} className={textClasses}>
{props.text}
</p>
</div>
);
}
.descriptionContainer {
padding: 16px 0;
  &__text {
font-size: 16px;
    &.u-red {
color: red;
}
&.u-large {
font-size: 24px;
}
}
}

This doesn’t remain as flat as other BEMy SCSS, but it can be less frustrating re:BEM modifiers!

Oh That was Simple 👯

There isn’t much more convincing that needs to be done! If you’re familiar with skill full ways to write SCSS with BEM, and you’ll write maintainable name-spaced components all the time. It’s important to remember that making use of practices like CSS naming conventions (BEM or otherwise) helps when app begins to scale. Yes, you may think that you’re fine with winging your naming conventions, but after a few features you’ll run into more and more classing styles and tangly over-specific CSS.