Still Limiting Use of CSS-in-JS

Published on

At work MUI is our UI framework, and for better or worse it comes with Emotion.js as a hard dependency baked in, but we also use Next.js which provides options for more raw, but still modularized, CSS. So many options isn’t always a good thing, but I find myself more and more wanting to reach for css modules.

Why we want to limit our reliance on Emotion.js

For a more in depth discussion on css-in-js runtime performance issues see. Why We’re Breaking Up with CSS-in-JS, but load performance matters too, and isn’t touched in that post, though I do allude to that in my previous post on this topic. Important to load performance is the fact that not all bytes are created equal. CSS files are easier to parse and feed directly to the browsers styling engine vs shipping css inside of js files, parsing it as js, and having the js runtime compute class names to add to the DOM and shuttle it off the composed style rules to the style engine. Now, how much of that performance consideration actually matters for our use case? Honestly probably it isn’t a major issue currently, but hey, one way to keep it from being something to worry about down the road is to engineer things efficiently from the get go, of course so long as the cost is small and you are not spending to much time and resource optimizing prematurely, but I don’t think that is the case here. Using css modules rather than shared styled components in MUI is pretty low effort, and to move to css modules when sx props gets unwieldy is a similarly low bar. Additionally the benefits are not just end users (UX), but the developer experience (DX) can be maintained or improved too - more readily available to use browser built in css dev tool for example. - some of the DX benefit will be subjective. I personally like working in native css more for a number of reasons, but mileage may vary.

It’s hard to articulate succinctly but having the code that shows up in the DOM look like

<div class="MuiBox-root css-0">
  <p class="MuiTypography-root MuiTypography-body1 FormItemCard_labelMain__WZN_X css-5ykhr3-MuiTypography-root">Scope 1</p>
  <p class="MuiFormHelperText-root MuiFormHelperText-sizeMedium MuiFormHelperText-contained FormItemCard_labelExtra__QfjuL css-1xl72qf-MuiFormHelperText-root">Some helpful addendum text stuff here</p>
</div>

ends up just being more opaque and tangled to reason about vs this more simple item with just css modules:

<div>
  <p class="FormItemCard_labelMain__WZN_X">Scope 1</p>
  <p class="FormItemCard_labelExtra__QfjuL">Some helpful addendum text stuff here</p>
</div>

Tradeoffs

Advantages:

Disadvantages

Current Approach

Theme level modifications use Theme.tsx or global.css

For simple customization of a particular component prefer using sx props. As complexity increases or if performance issues become a consideration reach for the css modules approach built in to Next.js. Avoid MUI styled components for now.

Challenges

Mixing sx and and css modules is an easy pit to fall into, and sort of gets the downsides of each approach, plus the confusion of intermixing. Avoiding that would have to be enforced by discipline and convention rather than linting rules for now at least.

Another issue with css modules is how we keep the Theme.jsx file that MUI uses and the css aligned. With the standard MUI theme there are no CSS vars set, so to get theme vars into css is a manual process as well is keeping them in sync. An option we are exploring is using the new “experimental” MUI theming approach. With that MUI puts all settings from our Theme.jsx file in as css variables. And I have a branch where this is seems to be working without any issues, but we’re hesitant to rush into anything labeled “experimental” - hoping MUI team keeps this moving forward.