DEV Community

loading...

Your own CSS-in-JS with PostCSS

Hadeeb Farhan
Updated on ・3 min read

The Why

Let's start by stating how much I love TailwindCSS. Check it out if you are not familiar with it.

Once you start writing styles alongside your component code, let it be any CSS-in-JS library or tailwindcss, there is no going back.

While using Tailwind, at some point you will have to deal with CSS classes.

There were some component libraries for carousel, modal, etc which added classes to HTML elements and I had to add style them using those classes.

Adding a new CSS file just for these brings a lot(?) trouble.

  • create a new file
  • name that file (nobody likes naming things)
  • create a wrapper class / nested classes in case you have multiple instances of the component and don't want the styles to leak.

Bringing in a CSS-in-JS library just for this, seemed overkill.

So, as a normal developer, I just wanted to reinvent the wheel, plus it could be a fun little experiment.

The How

My code is processed by babel to transpile JSX and all that new ESNext syntax sugars and features.

Can babel take my CSS and replace it with a classname?

I could create a babel plugin for that (I don't know how to do that)...
OR
I could write a babel macro

Read more about babel macros here.
How to write simple babel macro

Now that I have access to the CSS, I can vendor prefix it, use nested classes (this was the major requirement), etc using PostCSS.

PostCSS is basically babel for CSS. If you are writing CSS and using a build chain, probably you are using PostCSS. If you are thinking of doing something on CSS, probably there is a PostCSS plugin for that. The recommended way of using tailwindcss is using it as a PostCSS plugin.

autoprefixer and postcss-nested were the plugins I needed. These plugins add vendor prefixes and unwrap nestings in the CSS, just as their name suggests.

Now that I can generate valid prefixed CSS, it has to be injected to the DOM at runtime. The runtime can be so small as it's only function is to inject the style.

So code like this is transpiled to

import { css } from '.../css.macro'
css`
  display: flex;
`

something like this

import { css } from '.../css.runtime'
css('.someString','.someString{display: -webkit-box; display: flex;');

See the code here

What's Next

The next steps were to minify the generated CSS and create CSS from style objects. Just adding postcss-csso and postcss-js to the mix did the job. I love how easy these tools makes it to create awesome things.

See the final code.

Tip: If you are using VSCode, use vscode-styled-components to get syntax highlighting on CSS templates.

Links

Discussion (0)