Osamah Aldoaiss

Why we use CSS-in-js

Disclaimer: This is an opinionated post, sharing our experiences and transition from one technology to the other over the span of a year and a half. It might not apply to you and you might have other challenges/limitations in your project.

In the last few days a new CSS vs. CSS-in-JS (CiJ) debate started, fuelled by this gist from Sunil Pai.

He outlines his position about this topic and why he thinks CiJ is the natural evolution to CSS. You should definitely give it a read plus the small dialogue between Sunil and Snook in the comments.

Unfortunately there has been a lot of hate thrown at him and everyone who is using CiJ, I would like to address it with an example from a fairly complex web-app.


The Beginnings 🏗

In early 2017 (I was not part of the company yet) the company decided to do a complete Refactor of it‘s slow Meteor app with sometimes 15 seconds load times, to a much more modern Tech Stack in React and GraphQL. So in July the team started with this project.

As the developers at the start of this endeavour where not experts in setting up a Component System snd just started with React, they decided to use React Bootstrap for styling, which reduced the possibilities of the Styling stack to CSS or SASS.

When me and my friend (a Senior UI/UX Designer) joined together towards the end of the year, this was not enough for us. We wanted to build a complex Design System that fit the brand and gave us more speed. But the refactoring project was going to its end and big changes were not possible, so we did our best and we introduced CSS Modules to the stack.


CSS Modules 📦

Now even though the transition to CSS Modules was easy this introduced a lot of challenges:

  • How do we add multiple classes? The classNames library or concatenation?
  • How to apply new styles when some prop or something on the page changes?
  • How do we reuse styles?
  • Etc…

A lot of questions popped up and there was no clear convention, as there was no Lead Developer at that time, so many different coding styles were introduced and we were never really happy with that approach.

.button {
/** to override bootstrap styling */
compose: unstyled-btn from '../../styles/button.scss';
display: inline-flex;
justify-content: center;
align-items: center;
border: 1px solid #66aacc;
background: transparent;
// ...
}

Styled-components 💅🏽

As soon as the refactoring project finished, I started developing a stand-alone project for the Booking Process, so I had the chance to start from scratch and implement the Design System, that we wanted from the start. The result of that was our internal UI-Kit, built with styled-components.

The way we approached it was building for example the Button styles, that react to different props passed to it. For example if it is a link it will be an a-tag or if it’s a secondary Button it will look different.

// styles.js
import styled from 'styled-components';
export const Button = styled('button')`
display: block;
align-items: center;
color: ${({ primary }) => (primary ? 'blue' : 'white')};
...;
`;
// Button.js
import { Button } from './styles';
<Button primary>This is a Button</Button>;

The Final Evolution 👩‍🎤

Now the UI-Kit was the only part built in styled-components, for the application we still used CSS-Modules. When we tried to use styled-components, we suddenly got an issue with running multiple instances, so we made the seamless move to emotionJS.

Now the switch was easy, just a different import with saved us lots of trouble. This is what we are using now with a migration to emotion 10 soon.

Now how does our code look like when we write a component?

We are not using the object notation or the css prop. We are just writing css and exporting a styled component, so we then can reuse it across multiple parts of the app. This has proven to be very effective and increased our productivity . It also reduced the way we look at css classes and selectors differently as we do not need to worry about them at all anymore. Each div, each input is its own block that can be reused without any worries and in the worst case.

We are now more than 200 UI components in the Design System deep and we never had any issues with overriding styles due to the cascade or naming overlaps. Especially in a small team with Junior Devs, we can not afford to just trust that they don’t do things wrong, no matter how amazing they are.

For example a Navigation example:

import styled from 'react-emotion';
import { NavLink } from 'react-router-dom';
import { Icon } from '@homelike/ui-kit';
export const Header = styled('header')`
display: grid;
grid-template-columns: 24px 1fr 24px;
align-items: center;
padding: 0 ${({ theme: { spacing } }) => spacing * 2}px;
`;
export const Logo = styled(Icon)`
display: block;
`;
export const Spacer = styled('div')`
display: block;
`;
export const Menu = styled('div')`
display: flex;
justify-content: center;
align-items: center;
height: 100%;
`;
export const MenuItem = styled(NavLink)`
margin: 0 ${({ theme: { spacing } }) => spacing}px;
height: 72px;
line-height: 68px;
font-size: ${({ theme: { fontSizeMedium } }) => fontSizeMedium};
padding-top: ${({ theme: { spacing } }) => spacing * 0.25}px;
color: ${({ theme: { gray4 } }) => gray4};
text-decoration: none;
white-space: nowrap;
cursor: pointer;
&.isActive,
&:hover {
border-top: 4px solid ${({ theme: { primary } }) => primary};
padding-top: 0;
text-decoration: none;
color: ${({ theme: { gray1 } }) => gray1};
}
`;
import React from 'react';
import { Translate } from 'react-redux-i18n';
import { Header, Logo, Menu, MenuItem, Spacer } from './styles';
const Navigation = ({ email }) => {
return (
<Header>
<Logo name="logo-small" fill="primary" color="primary" size="large" />
<Menu>
<MenuItem to="/payments" activeClassName="isActive">
<Translate value="shared.header.payments" />
</MenuItem>
<MenuItem to="/change" activeClassName="isActive">
<Translate value="shared.header.change" />
</MenuItem>
</Menu>
<Spacer />
</Header>
);
};
export default Navigation;

This is much more readable to our team and easier to debug if we look at the React Dev Tools. One might like it or not, and that is fine 🤗


Conclusion

Now as a conclusion let’s be clear: this was our story and our path. I am still using CSS/SASS in other projects and I use and understand the new CSS features, that are amazing. But emotion-js just gives me so much more then that, composability and dynamic styling in different situations. The perfect mix, when building a complex application.

HTML/CSS gave me my first job while I was in middle school and I grew and evolved since then, so did my tools and my needs. And that is okay.

;