CSS-in-JS: What happened to readability?
Tags: react, css, html, beginners
Published: 2020-11-06 07:07:19

When I first started using [BEM](http://getbem.com/) (block-element-modifier) early in my career, I distinctly remember how refreshing it was to have a system to name and assign semantic meaning to our otherwise esoteric CSS blocks. Almost immediately (once I understood the rules) it became easy to glance at some CSS and visualise the changes that will be applied to elements in their various states. Love it or hate it, something about its simple underlying principles stuck with me.

It looked something like this…

```css
.my-button { }
.my-button.my-button__icon { }
.my-button.my-button--primary { }
```

Nowadays, most of us are using CSS-in-JS libraries like [styled-components](https://styled-components.com/) or [emotion](https://emotion.sh/) (which are fantastic libraries btw), but all of a sudden it seems like we forgot about the helpful methodologies we learned with [BEM](http://getbem.com/), [OOCSS](https://github.com/stubbornella/oocss/wiki) and [SMACSS](http://smacss.com/). As a result CSS-in-JS that you encounter in the wild is hard to read and reason about.

You might be familiar with seeing code like this:

```javascript
styled.button`
 background: ${props => props.primary ? "you" : "didn't"}
 color: ${props => props.primary ? "read" : "this"};
 font-size: 1em;
 margin: 1em;
`;
```

In this case, properties for the `primary` modifier are computed individually, carrying an implicit runtime cost, which scales poorly as more modifiers are eventually added. More importantly, this carries **substantial cognitive overhead** for future maintainers, trying to understand how and when properties are being applied. A point proven by the fact that you probably didn’t read that code block at all (Check again 😉).

Now you’re the next developer to come along and attempt to add a `disabled` state to this button. You might be inclined to continue this pattern and do something like this…

```javascript
function getBackgroundColor(props) {
 if (props.disabled) return 'grey';
 if (props.primary) return 'blue'; 
 return 'white';
}
function getColor(props) {
 if (props.disabled) return 'darkgrey';
 if (props.primary) return 'white'; 
 return 'black';
}
styled.button`
 background: ${getBackgroundColor};
 color: ${getColor};
 font-size: 1em;
 margin: 1em;
`;
```

But this only further exacerbates the problem by creating yet another layer of indirection.. OH NO 😱 Not only do you have to compute this function in your head, you now have to locate these helpers 🤯

For better or worse styled-components is totally unopinionated about these things, if you’re not careful you might inadvertently allow bad practices to propagate through your components. Sure, you could BEM-ify this code in styled-components, but my point is that you’re not forced to by the API. Even so, BEM-like methodologies are no better because they’re merely a set of rules and rules are great only until someone breaks them 👮‍♂️!

CSS-in-JS actually provides the perfect opportunity for an API abstraction to solve this very problem 🎉 by abstracting away the messy details of a methodology and leaving you and your colleagues with a library that guards you from these implicit issues.

**<Start plug>**
This was my motivation to build Trousers 👖 ([v4 coming soon](https://github.com/danieldelcore/trousers/pull/84))
**</End plug>**

😅

but I’m not the only one thinking about this! New libraries like [Stitches](https://stitches.dev/) are popping up all over the place, taking a similar approach to shepherding users into using good patterns through API design. Leaving us with the best of both worlds!

Trousers as an example provides grouped properties via modifiers…

```javascript
import css from '@trousers/core';
const styles = css('button', { backgroundColor: 'blue' })
  .modifier('primary', { backgroundColor: 'white'})
  .modifier('disabled', { backgroundColor: 'grey' });
```

Named modifiers controlled via props…

```javascript
/* @jsx jsx */
import css from '@trousers/core';
import jsx from '@trousers/react';
const styles = css('button', { backgroundColor: 'blue' })
  .modifier('primary', { backgroundColor: 'white'})
  .modifier('disabled', { backgroundColor: 'grey' });
const CustomButton = (props) => (
  <button 
    css={styles}
    $primary={props.isPrimary}
    $disabled={props.isDisabled} 
  />
);
```

Themes as css variables, allowing for even less dynamic css and runtime cost.

```javascript
css('button', { backgroundColor: 'blue' })
  .modifier('primary', { backgroundColor: 'var(--color-primary)' })
  .theme({ color: { primary: 'red' });
```

And all of the examples above will only ever mount `1 + number of modifiers`, regardless of component state and active theme.

All possible because CSS-in-JS provides us with layer of abstraction to do this work!

So my ask for you to takeaway from this blog is not to necessarily use my library, but start to think the [cognitive science](https://en.wikipedia.org/wiki/Cognitive_science) behind how we write CSS-in-JS today and how you can start incorporate these principles into your apps and libraries in the future to improve the readability and maintainability of your code!

*Quick aside:* Trousers is simply standing on the shoulders of other great libraries, so full credit to the people and libraries that inspired it!

Please do yourself a favour and checkout these fantastic libraries if you haven’t already:

- [Compiled](https://compiledcssinjs.com/)
- [Stitches](https://stitches.dev/)
- [Styled Components](https://styled-components.com/)
- [Emotion](https://emotion.sh/)

Thanks for reading 👋