The tiniest CSS-in-JS solution for your open-source React components
Tags: react, javascript, webdev, opensource
Published: 2021-02-18 08:29:34

Hey there! My name is Vlad and I'm fascinated by the development of JavaScript micro-libraries. My primary projects at the moment are:

- [**react-colorful**](https://omgovich.github.io/react-colorful) — the tiniest and fastest color picker component for React and Preact apps (14 times lighter than react-color)
- [**wouter**](https://github.com/molefrog/wouter) — a minimalist-friendly 1.3KB routing solution for React and Preact
- [**omgopass**](https://github.com/omgovich/omgopass) — a tiny 0.3 KB and ultra-fast memorable password generator (600 times faster than password-generator)

**react-colorful** is the only project that ships both JS and CSS. I want to share with you the challenges we encountered while developing it. You might find our experience useful in making your open-source React components lighter.

## 📦 Problem

Since its first release, **react-colorful** has included a CSS file that developers have to import:

```jsx
import { HexColorPicker } from "react-colorful";
import "react-colorful/dist/index.css"; // 👈 this one
```

In terms of bundle size, everything was super cool because we wrote all styles as CSS files that were then compressed and minified by a bundling tool. 

It seemed like a good solution, but we've started receiving complaints from many developers that were unable to use the styles. It is quite common in the React ecosystem to use libraries like [Emotion](https://emotion.sh/), [Styled-Components](https://styled-components.com/), or other CSS-in-JS libraries exclusively and to entirely forgo the inclusion of a style loader. As such, usage of **react-colorful** would necessitate the alteration of build configurations for these users to be able to access the default styling.

Moreover, many component libraries and UI kits are CSS-in-JS exclusive, so the CSS-only approach makes it difficult for the picker to be compatible.

## 👩‍🎤 Why not just use an existing CSS-in-JS solution?

In [my last post](https://dev.to/omgovich/react-colorful-1-8-kb-color-picker-for-react-fast-dependency-free-customizable-and-accessible-8le), I mentioned that **react-colorful** aims to be a zero-dependency package and we didn't want to change that by adding a CSS-in-JS framework, such as Emotion.

The entirety of **react-colorful** costs about 2 KB, but installing emotion would make the size of the package almost 7 times bigger. Of course, there are tiny CSS-in-JS libraries like [goober](https://github.com/cristianbote/goober) that cost about 1KB, but we didn't feel like we need the entire library since our styles are not dynamic.

Installing an extra dependency on other developers' projects does not seem justified to us.

## 🗜 The tiniest solution

In order to achieve our goals, we decided to find a simple way of injecting styles into the page just like how CSS-in-JS libraries do that.

I use [Microbundle](https://github.com/developit/microbundle) to build my open-source projects and love it a lot. It's a zero-configuration bundler for tiny modules, powered by Rollup. 

Most bundlers, Microbundle included, save processed styles to the disk as a CSS file. Because we wanted to have the styles in JS, [we asked](https://github.com/developit/microbundle/issues/744) Jason Miller, the author of Microbundle (amongst many other notable projects), to provide us with a way to import processed CSS as a string into JavaScript and he generously added a [new option](https://github.com/developit/microbundle#css-and-css-modules) to Microbundle:

```jsx
// with the default external CSS:
import "./foo.css";  // generates a minified .css file in the output directory

// with `microbundle --css inline`:
import css from "./foo.css";
console.log(css);  // the generated minified stylesheet string
```

*It is not necessary to use Microbundle; you can use any build tool that you'd like, just make sure to read up on the docs to configure it properly.*

Then we created a [simple hook](https://github.com/omgovich/react-colorful/blob/master/src/hooks/useStyleSheet.ts) that creates a `<style>` tag containing the styles for our component. As soon as the component renders the first time, this hook appends the tag to `<head>`.

```tsx
import { useLayoutEffect } from "react"
import styles from "../css/styles.css";

let styleElement;

const useStyleSheet = () => {
  useLayoutEffect(() => {
    if (typeof document !== "undefined" && !styleElement) {
      styleElement = document.head.appendChild(document.createElement("style"));
      styleElement.innerHTML = styles;
    }
  }, []);
};
```

## 👍 Results

Since it no longer requires importing CSS separately, the usage of the [**react-colorful**](https://github.com/omgovich/react-colorful) became much simpler. Now the component can be used with any CSS-in-JS project or component library.

The hook's gzipped size is about 150 bytes, and I suspect it's one of the smallest ways of shipping CSS for a React component.

## ❤️ Thanks for reading

We care about size, performance, and accessibility. I hope that the React community shares our values and will find [**react-colorful**](https://omgovich.github.io/react-colorful/) useful for further projects.

It will help us a lot if you star the repo on GitHub or share the link to this article with your friends 🙏

{% github omgovich/react-colorful %}