What is the best way to distribute styles with npm package?

stereobooster - Jun 3 '19 - - Dev Community

Let's say we have an npm package with React components. These components have/need styling. Some styles are overridable, for example, colors or dimension (aka theming). Some styles are not overridable, for example, some component-specific positioning, imagine styles that are needed to position cells in calendar component.

CSS files

We can do it old-school way by providing CSS files. If the consumer uses webpack or Parcel they can do something like this:

import { Component } from "package"
import "package/styles.css";
Enter fullscreen mode Exit fullscreen mode

If there is no bundler developer would need to put styles in the header

<link href="package/styles.css" rel="stylesheet">
Enter fullscreen mode Exit fullscreen mode

How to do theming? We can try to use CSS variables. But the downside is that there is no safety in that process. What if instead of --primarycolor: red; developer writes --primary: red;, there is no type system no runtime check that will prevent the error.

As well stylesheets expose implementation details. Stylesheet becomes part of the public API. If we need to change the internal markup of the component, it can affect the structure of CSS, and if it does we will need to bump the major version of the library (because it can be breaking change for somebody).

We will need to support unique specifiers (class names or similar) for our components. We can try to take Reach UI approach and use data params instead of classes, for example [data-reach-menu-item]. But again, there is no safety in this approach, what if developer mistyped specifier or specifier changed with the major library update.

CSS-in-JS

We can use emotion or JSS to style components. Question of theming is solved. No issue with unique classifiers. There is safety in place - we can use typescript or add runtime checks.

But it will have runtime, which can be an issue (from performance POV). It will increase the size of the component (we can use peerDependencies, but then the package is not consumable without bundler). What if the developer uses more than one component and each comes with its own CSS-in-JS solution 😱? We will need to do the additional configuration for SSR.

Other

We can use style property as well, but we need to write some code to do theming (maybe with Context).

We can use className prop and assume that consumer will use CSS Modules. Again, we need to think about how to pass it to deeply nested components (maybe with Context?).

Use CSS-in-JS solution, which could be compiled away with a zero-runtime solution like linaria or astroturf, so the developer who doesn't want runtime can remove it, but still have all DX benefits. I haven't seen this in practice, this is just my dream.

What would you recommend?

As you can see there are trade-offs in each approach. What would you recommend? Did you try to solve a similar task? Share your experience.

Photo by Erik Eastman on Unsplash

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .