The ugly part of CSS-in-JS
Andreas Sander

Andreas Sander @andi1984

Location:
Saarbrücken
Joined:
Jun 18, 2019

The ugly part of CSS-in-JS

Publish Date: Sep 28 '23
8 14

One often-overlooked aspect of CSS-in-JS is its "dark side"—the "JS" part. What does this mean? Essentially, when you're writing your styles within JavaScript, you expose yourself to the quirks and intricacies of JS itself.

The Issue Illustrated

Consider the following example:

You might notice that the styles defined in IBreakStyles aren't applied as expected. Digging into the element with your development tools reveals a complete absence of styles.

The Root Cause

The culprit is a stray closing curly bracket within the template literal:

const IBreakStyles = styled.p`
  padding: ${({ $count }) => $count + "px"}}; /* <-- The offender */
  color: red;
  background-color: blue;
`;
Enter fullscreen mode Exit fullscreen mode

What happens is that the CSS-in-JS library (in this case, styled-components) interprets the template literal in a specific way. This leads to parsing the CSS via JavaScript, and the stray curly bracket disrupts the intended behavior—likely closing some parent block in the JS logic.

The Silent Problem

The real issue is the absence of any alert mechanism: no errors are thrown, and no red squiggly lines appear in your editor to warn you. If you're fortunate, your editor's CSS-in-JS tooling might catch this, but that's not a guarantee.

A Thought to Ponder

Given these complexities, it's worth questioning if a separation of concerns—CSS in CSS files and JS in JS files—might not be a more foolproof approach, much like the "good old times."

Best regards,

Andi

Comments 14 total

  • Eckehard
    EckehardSep 28, 2023

    CSS itself has some conceptual issues and limitations. If you use it the way it was initially intended, it works pretty straightforward. But some solutions try to overcome this limitations. If that means, that each element is marked with a classname behind the scenes, this will possibly bloat your files and cause more problems than it solves.

    Any solution should be minimally invasive. If you just need some very conventional styling, it should allow to use the "good old solutions" and schould not affect your workflow.

    • Andreas Sander
      Andreas SanderSep 29, 2023

      I agree 100%!

      But some solutions try to overcome this limitations.

      I also see this point you made and there is definitely also a good/"beautiful" part of CSS-in-JS. But it is as you said: Choose your tools wisely for the work you want to do and the goals you want to achieve.

  • Yeom suyun
    Yeom suyunSep 29, 2023

    I don't really like styled-components, but I think the examples are too limited.
    However, with a few improvements, I think libraries that use templates like styled-components could also warn about typos, just like vanilla-extract does.

    • Andreas Sander
      Andreas SanderSep 29, 2023

      @artxe2 I agree and partly they do as part of editor extensions (cf. @joelbonetr comment below). But I think – although VSCode is pretty much defacto standard editor nowadays – they can not assume that the user has their extension installed or even using another editor/IDE where there is no extension available.

      I would personally like to see – at least – a warning in the dev console or something similar. Thus I agree 100% with you!

      • JoelBonetR 🥇
        JoelBonetR 🥇Sep 29, 2023

        This is a concept issue. If we get to have all capabilities pre-installed and available, the IDE would be super slow and inconvenient overall. Allow me to drill down the topic:

        The language I use most is JS/TS, there's native support in VSCode so it's not much big of a deal, but lets dig deep.

        In some projects I use NX to handle a monorepo, for which I need this extension.

        In most projects that implement React -or Next JS for the record- I use styled-components as it simplifies the smart-dumb architecture and it has certain benefits I love, in this situation I need this extension

        I may use RapidAPI extension to test the endpoints I code or third party ones when doing an integration.

        In certain projects in which I handle the data as well I might use PGAdmin sometimes but also SQLTools extension depending on the situation.

        In all use-cases I'm using GitLens to work with git faster and better.

        But then... then I switch to C++ sometimes, for which I need 4 extensions, installed through the C/C++ extension pack

        I might switch to Python for other tasks, for which I need the python extensions and the Jupyter ones .

        I have more extensions installed but the key here is that I only enable those that I need at that given moment, otherwise certain extensions can cause conflicts between each other.

        From the PoV of JS, a template string is just... a string.

        You'd love to see built-in code analysis on template strings for styled-components but another dev might work on email templating and they would love to see spell checking capabilities built-in template strings, and probably html color codes, just to add an example. In which case you may install the Styled-Components extension and the other would love the ES6-string extension.

        And that's the neat part of VSCode, that you can install or develop extensions to fill the gaps and comply with your needs! 😁 But having everything built-in by default would be quite counter-productive because certain parts will always be bloatware -software that's pre-installed but the user will never use-, messing up the dev experience for everyone.

        Hope it helps on understanding the big picture 😃

        • Andreas Sander
          Andreas SanderSep 29, 2023

          You're right about that and VSCode Profiles are very helpful also in that regard to have different profiles maybe for different people, but also the suggested extensions you can define for every particular repo.

          Still – call me an old guy or something :) – I think we can not assume also nowadays that users have those tools at their hand or probably they just don't know about them. That's why I would love to see at least some glimpse of a warning either on the CLI (if it can be detected at compile time) or a warning in the client (if it only gets detected at runtime). I admit that a console.warn would not be optimal, but at least as a dev checking your project with devtools, you will get an idea of what is wrong.

          But as you said, there is probably a tool, extension/plugin for it to include into your IDE and you're safe regarding such issues.

  • Magne
    MagneSep 29, 2023

    Template literals may be the culprit of the problem here. There are some CSS-in-JS libraries that don't use template literals, and provide type safety (squiggly lines).

    Check out Tamagui.dev for best-in-class CSS-in-JS experience for React and React Native (works crossplatform, with SSR!), where styles are pre-computed at build time, so there's no JS to change styling at runtime. It also has type-safe styles.

    Alternatively try Panda CSS, which is also build time CSS-in-JS (the successor to Chakra UI), also has type-safe styles, and works across more rendering libraries, like Qwik.

    • Andreas Sander
      Andreas SanderSep 29, 2023

      @redbar0n Thanks for all those infos. I haven't heard about those and it is definitely interesting to see compile vs. runtime discussion. I will have a look at those mentioned libs and I assume those are also valuable to other readers of the article. Many thanks!

  • JoelBonetR 🥇
    JoelBonetR 🥇Sep 29, 2023

    Just install the Styled Components plugin in VSCode and it will warn you.

  • 𒎏Wii 🏳️‍⚧️
    𒎏Wii 🏳️‍⚧️Sep 29, 2023

    I don't really like the idea of writing CSS as strings within JS only for those to then get parsed into some internal representation and serialised back into CSS code.

    In my opinion, it makes much more sense to write styles directly in the form of javascript code and let the browser take care of checking and reporting whether the syntax is all correct. Nested JS objects can get relatively close to CSS both in syntax and in functionality.

    Ideally I'd want to write something like

    const my_styles = css({
       padding = CSS.px(whatever),
       color = 'red',
       backgroundColor = 'blue'
    })
    
    Enter fullscreen mode Exit fullscreen mode
  • Mark M. Florida
    Mark M. FloridaSep 29, 2023

    CSS-in-JS is an anti-pattern, especially as implemented with Styled Components.

    CSS modules are what Styled Components wishes it was. (they were?)

    😎

  • Ben Sinclair
    Ben SinclairSep 30, 2023

    CSS-in-JS comes with a lot of problems, and even "fixing" it with things like smarter linters doesn't get around the fact that you're painting yourself into a corner.

    I think it would be better to keep the styles separate.

  • Matt Kenefick
    Matt KenefickOct 1, 2023

    This article could just say "The ugly part of CSS-in-JS is CSS in JS." And that's it.

    Don't put CSS in JS.

Add comment