Fixing Class Composition in Tailwind CSS

This page summarizes the projects mentioned and recommended in the original post on dev.to

Our great sponsors
  • SurveyJS - Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App
  • WorkOS - The modern identity platform for B2B SaaS
  • InfluxDB - Power Real-Time Data Analytics at Scale
  • Tailwind CSS

    A utility-first CSS framework for rapid UI development.

  • There are many opinions on how to deal with such cases. Some recommend using the @apply directive for your components’ base styles. Others argue that you should already consider all the possible variants of your component and use JavaScript logic to apply proper classes based e.g. on the component’s props.

  • twin.macro

    🦹‍♂️ Twin blends the magic of Tailwind with the flexibility of css-in-js (emotion, styled-components, solid-styled-components, stitches and goober) at build time.

  • One of the more promising alternatives is twin.macro - a Babel macro that processes Tailwind classes to generate JS objects understandable by various CSS-in-JS libraries. The developer experience (DX) of using it is amazing as you not only get all of Tailwind’s features without much change to your code, but you also get much more flexibility - all that on top of the traditional benefits of CSS-in-JS. Here’s an example code:

  • SurveyJS

    Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App. With SurveyJS form UI libraries, you can build and style forms in a fully-integrated drag & drop form builder, render them in your JS app, and store form submission data in any backend, inc. PHP, ASP.NET Core, and Node.js.

    SurveyJS logo
  • vite

    Next generation frontend tooling. It's fast!

  • While not too long, css`@apply is a lot to repeat for every class you want to “compile”. That’s why using Vite and some Rollup plugins (Vite uses Rollup under the hood) I was able to shorten it into this:

  • babel-plugin-macros

    🎣 Allows you to build simple compile-time libraries

  • One of the more promising alternatives is twin.macro - a Babel macro that processes Tailwind classes to generate JS objects understandable by various CSS-in-JS libraries. The developer experience (DX) of using it is amazing as you not only get all of Tailwind’s features without much change to your code, but you also get much more flexibility - all that on top of the traditional benefits of CSS-in-JS. Here’s an example code:

  • vanilla-extract

    Zero-runtime Stylesheets-in-TypeScript

  • Vanilla-extract allows you to utilize TypeScript as your CSS preprocessor, just like Sass. On top of that, it comes with Sprinkles - an atomic CSS framework that allows you to reproduce Tailwind’s utility classes.

  • unocss

    The instant on-demand atomic CSS engine.

  • Now, I’d like to mention one more Tailwind alternative that might be worth your attention - especially in regards to class composition - UnoCSS.

  • Rollup

    Next-generation ES module bundler

  • While not too long, css`@apply is a lot to repeat for every class you want to “compile”. That’s why using Vite and some Rollup plugins (Vite uses Rollup under the hood) I was able to shorten it into this:

  • WorkOS

    The modern identity platform for B2B SaaS. The APIs are flexible and easy-to-use, supporting authentication, user identity, and complex enterprise features like SSO and SCIM provisioning.

    WorkOS logo
  • linaria

    Zero-runtime CSS in JS library

  • After exploring all the above alternatives (and more), I’ve decided to implement my own, custom solution. For that, I’ve turned to Linaria - a true zero-runtime CSS-in-JS library.

  • astro

    The web framework for content-driven websites. ⭐️ Star to support our work!

  • The above config is what I used to get the shorthand and Liniaria working in Vite. To give you an overview of how it works - the twis first replaced with css\@apply and then the css template literal tag is auto-imported where necessary. I’ve only used this setup with Vite and Astro (Vite-based) so I don’t know how hard it’d be to get it working in other bundlers (though pure Rollup should work as well).

NOTE: The number of mentions on this list indicates mentions on common posts plus user suggested alternatives. Hence, a higher number means a more popular project.

Suggest a related project

Related posts