DEV Community

Francesco Agnoletto
Francesco Agnoletto

Posted on • Edited on • Originally published at decodenatura.com

About CSS-in-JS and React

CSS-in-JS is something I've been unable to stop using on both personal projects and work.
CSS has been introducing more and more features, making SCSS less of an obvious choice.

At the same time, CSS-in-JS libraries entered the scene. They add some interesting features: Server-Side-Rendering, code splitting as well as better testing.

For the purpose of this article, I will be using EmotionJS and React. EmotionJS features TypeScript support, easy setup, and testing integration.

Advantages of CSS-in-JS

Being JavaScript, it offers all the features modern front-end development relies on.

Server-Side Rendering and code split with Emotion

Server-Side Rendering (SSR) with Emotion and React is simple. If you have React SSR enabled then congratulations! You have enabled it for Emotion as well.

Code splitting is pretty much the same.
Emotion is JavaScript so it will code split just like the rest of the application.

Sharing props between React and Emotion

Building styles based on classes can become quite complicated for big codebases.
In most cases, having each prop become a class can increase the verbosity of the code.
Having props determine styles without classes would cut a lot of unnecessary code.

const classes = `${className} ${theme || "off-white"} ${size || "medium"} ${border !== false ? "with-border" : ""} ${inverted ? "inverted" : ""} ${disabled ? "disabled" : ""}`;

The example above shows how convoluted a template literal can become.

This can be avoided by leveraging Emotion.

import { css } from "@emotion/core";
import styled from "@emotion/styled";

const themes = {
  red: css`
    color: pink;
    background: red;
    border-color: pink;
  `,
  blue: css`
    color: light-blue;
    background: blue;
    border-color: light-blue;
  `,
};

const sizes = {
  small: '8px',
  medium: '12px',
  large: '16px'
}

const disabledCss = css`
  color: grey;
  border-color: grey;
`;

/* Defining the button with the conditional styles from props */
const StyledButton = styled.button`
  ${(props) => themes[props.theme]};
  font-size: ${(props) => sizes[props.size]};
  border: ${(props) => props.border ? '1px solid' : 'none'};
  ${(props) => props.disabled && disabledCss};
`;

/* And finally how to use it */
<StyledButton
  theme="red"
  size="medium"
  border={true}
  disabled={false}
>
  Hello
</StyledButton>

There are no classes to depend on. The styles are applied to the components, removing the classes layer.

New styles are easily added and even more easily removed, JavaScript handles variables far better than we handle classes.

These atomic styles are easy to share across the codebase. Being variables, they can be imported and exported to other files.

Testing Emotion and React

Style regression and changes have always been up to the developer to check manually. CSS and SCSS do not allow to test this in any meaningful way.

Jest allows to snapshot React components to see diffs in HTML, making sure changes are safe. In the same way, Emotion styles can be snapshotted.

Snapshotting CSS removes the need to have to check manually if the styles break when making new changes.
This can be a huge time saver for both developers and testers who can ship code with more confidence.

Achieving all this in Emotion is rather fast.

Add this to your Jest setup file

import * as emotion from 'emotion'
import { createSerializer } from 'jest-emotion'

expect.addSnapshotSerializer(createSerializer(emotion))

And it's done. When creating a snapshot, the EmotionJS output will be included in the snapshot.

Closing thoughts

CSS-in-JS has drastically changed the way to write CSS. Leveraging the most used programming language gives CSS new features to improve the way styles can be written.

Performance, maintainability, and testing are the core of a good application. CSS-in-JS offers improvements over older standards to all these issues.


originally posted on decodenatura

Top comments (0)