About CSS-in-JS and React
Francesco Agnoletto
Posted on April 6, 2020
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
Posted on April 6, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.