Skip to content

Instantly share code, notes, and snippets.

@troch
Last active October 18, 2020 17:52
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save troch/c27c6a8cc47b76755d848c6d1204fdaf to your computer and use it in GitHub Desktop.
Save troch/c27c6a8cc47b76755d848c6d1204fdaf to your computer and use it in GitHub Desktop.
Choosing a CSS in JS library

Choosing a CSS in JS library

Check comments below, this is only my opinion and a choice specific to my use case

We've architected a SPA to be universal-ready. It grew a lot, when we introduced code splitting we realised converting to CSS in JS was unavoidable in order to have pre-rendering and not load all our CSS up front. We've procrastinated on looking at CSS in JS properly, prioritasing immediate business needs, but kept an eye on industry evolutions.

Our CSS solution for components was a CSS companion file per component, imported with style / postCSS loader (with webpack) but no CSS modules: we were missing a tighter coupling between component rendering and styles. We were at the bottom of the CSS and componentization ladder, the following links have influenced us in choosing the right solution for us:

Shortlist

There is a vast number of libraries to choose from: https://github.com/MicheleBertoli/css-in-js.

CSS modules would have worked for us, and would have been a minimal effort (in term of refactoring and changing habits). However, we wanted to go further in our componentization approach. We discarded inline styles: they are restrictive, the trend is about dynamic style sheets, to enjoy CSS full power. We also discarded solutions which simply consist of embedding CSS in JS, and not embedding CSS in components.

We chose to highlight four libraries (non-exhaustive list):

  • styled-components
  • glamorous
  • styletron
  • fela

Other libraries we didn't evaluate but we could have:

  • JSS

Making a choice: fela

All libraries mentioned are excellent. Our experimentation and choice making was time-boxed, and at the end we feel we made what we think is the best choice for us and our circumstances, maybe not for everyone.

They are all inline CSS libraries (and not inline styles), so they support pseudo-elements, pseudo-selectors, media queries, prefixing and value fallbacks.

They also all support server-side rendering. Support for React Native was a nice to have (styled-components, fela, glamorous). We regarded atomic CSS (styletron, fela) as an implementation detail.

Syled-components uses raw CSS, other libraries use object literals.

We weren't going to base our choice on popularity: they all have safe levels of monthly downloads and activity in their repositories.

Fela was discovered when doing our research, we hadn't heard about it before, and it won the argument for mainly two reasons: flexibility and extensibility.

  • Flexible API: you can abstract away class names by wrapping elements with a styling HoC (like with styled-components, glamorous or styletron). Or you can use a styling HoC on a composite component, manually distributing class names. I view this as very important for componentisation (passing class names as props, avoiding to wrap components with elements) and for integration with 3rd party libraries.
  • Extensible: fela has plugins, reminding me of postCSS plugins. It adds to fela's flexibility. Existing plugins for pseudo selectors and media queries make working with object literals much better (onHover instead of :hover, etc...). It gives you power to create your own API / way of writing style objects. It also has enhancers which are basically renderer decorators. Fela uses atomic CSS which is reknown its bad developer experience. Fela offers a monolithic enhancer (with the option to include rule names) for a better DX.
@kentcdodds
Copy link

I agree with @davidkpiano ๐Ÿ‘

@troch
Copy link
Author

troch commented Jul 14, 2017

Thanks for the comments ๐Ÿ‘. I've amended the article, pointed to the comments ๐Ÿ˜„. It was actually not an easy choice to make, all modern and recent CSS in JS libraries are about CSS and componentization, and that's what matters!

@nickbalestra
Copy link

Thank you so much @troch for doing this. I'll follow up with one from our-side once we come up with our decision based on our specific use-case (not spa)

@aselbie
Copy link

aselbie commented Jul 14, 2017

@kentcdodds is your intent with Glamorous to maintain parity and converge with SC for the longer term? I.e. would it be safe to call Glamorous "SC without the parser"? Or do you see your approaches branching? I think I prefer the "just JS" approach, but SC seems to have the most momentum out of the styling-in-JS options, and I'd love to be able to benefit from that community and ecosystem.

@kof
Copy link

kof commented Jul 15, 2017

I wonder why JSS was left out from the final selection, any feedback?)))

@troch
Copy link
Author

troch commented Jul 15, 2017

@kof we missed JSS when making our selection, it would have made the list otherwise. Added a note.

@kentcdodds
Copy link

kentcdodds commented Jul 17, 2017

@aselbie, my intent is to maintain parity with what the users of glamorous want ๐Ÿ˜„ For example, styled-components recently added support for components as selectors and we decided to forgo that because it's already pretty straightforward to do that though less ergonomic, but it's not a practice we care enough to encourage that we want to make the codebase/api any more complex. At the same time, we have added some features because styled-components added them and we thought they were good ideas (after all, styled-components was the main inspiration for glamorous in the first place). In addition, there are several things that glamorous can do that styled-components cannot (like the built-in components that take styles as props, the css prop, and more). So it's mostly community driven. I don't expect the two to converge ever. But maybe!

SC seems to have the most momentum out of the styling-in-JS options, and I'd love to be able to benefit from that community and ecosystem.

It's unclear to me what you'd lose by using glamorous. There are a few libraries that expose styled-components as primitives, but most libraries support both (like polished or styled-system). In addition, there's a world of CSS-in-JS libraries that support objects which you have available to you with glamorous as well. It's not a small community ๐Ÿ˜„ In fact, styled-components has a pretty good head start on glamorous, and we're already almost half of the daily downloads ๐Ÿ˜‰

@mxstbr
Copy link

mxstbr commented Jul 18, 2017

styled-components has a pretty good head start on glamorous, and we're already almost half of the daily downloads

Sidenote: npm stats don't mean jackshit for production usage since they include other npm packages that depend on you. (like glamorous and storybook or styled-components and rebass) A high percentage on top of that is CI installs, not people. shrugs

@troch
Copy link
Author

troch commented Jul 18, 2017

For example, styled-components recently added support for components as selectors and we decided to forgo that because it's already pretty straightforward to do that though less ergonomic, but it's not a practice we care enough to encourage that we want to make the codebase/api any more complex

@kentcdodds sounds sensible. We have a rule around componentization and CSS: it was written in the context of using BEM, but is applicable to CSS in JS too.

"Never reference a parent or child component class name in a CSS file: it is for parents / owners to create components with the right class names (i.e. modifiers), and not for components to override their properties based on the context they find themselves in. Similarly, it is not for a component owner to override CSS properties of its children: it should instead create a component with the right properties, resulting in the right CSS class names being generated.

@streamich
Copy link

streamich commented Feb 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment