Im merging css-in-js and Tailwind
Tags: tailwindcss, css, react, typescript
Published: 2022-11-15 22:31:59

---
series: "TW Classed - Idea to Library"
---
I'm merging css-in-js and Tailwind. Let me explain.

## Why merge Tailwind with CSS-in-JS when twin.macro exists?

The first reason is reusability. Creating a button component which can vary via props requires manually mapping props to tailwind classnames. This gets very tiring very fast and makes it quite difficult to create React UI libraries with pure Tailwind.

The second reason is to improve my Typescript knowledge. It's not easy creating Typescript libraries, making them infer props, configurations all under the hood is even harder. And thus, my journey creating the library began.

## The requirements

I made a list of requirements for this library, these are specific to challenges I faced developing UI libraries and React components with Tailwind.

1. It must be able to merge multiple classnames
2. It must have support for toggling different classnames based on input
3. It must be able to create JSX like `button` or `span`
4. First class TypeScript support

## Inspiration

When trying to come up with a good API I only had to look in one direction. [Stitches.js](https://stitches.dev/). In my opinion, this is the best CSS in JS library made to date, and as such, it had the exact API I was looking to create. Please check their library out and give Modulz/WorkOS the credit they deserve!

## Introducing `@tw-classed/react` & `@tw-classed/core` public alpha

These are both in `alpha` stages as I'm still ironing out the Typescript types required to make them work. The types in `core` are not stable enough for advanced usage just yet.

`@tw-classed/react` is quite stable even for advanced Typescript usage, though I haven't performed any tsc performance tests nor heavy testing just yet. As such I've decided to only release these two libraries in a public alpha while I'm testing.

The full documentation is [here](https://tw-classed.vercel.app). Below is a tiny introduction to the libraries.

### `@tw-classed/core`

This is the framework agnostic core of the react library. It can be used standalone in vanilla JS to create dynamic Tailwind classes (or in other libraries when not using react). It simply acts as a class merger and toggler and can be used in any way imaginable.

```js
import classed from "@tw-classed/core";

const simpleButton = classed(
  "flex items-center py-3",
  "hover:bg-gray-200 focus:bg-gray-200" // Accepts any number of arguments
);

console.log(simpleButton()); // => "flex items-center py-3 hover:bg-gray-200 focus:bg-gray-200"

const button = classed(
  "flex items-center", // Apply your base styles
  {
    // Define your variants
    variants: {
      size: {
        sm: "py-2 px-4",
        md: "py-3 px-6",
        lg: "py-4 px-8",
      },
      color: {
        primary: "bg-blue-500 text-white",
        secondary: "bg-gray-500 text-white",
      },
    },
    defaultVariants: {
      size: "md",
      color: "primary",
    },
  }
);

console.log(button()); // => "flex items-center py-3 px-6 bg-blue-500 text-white"
console.log(button({ size: "sm" })); // => "flex items-center py-2 px-4 bg-blue-500 text-white"
console.log(button({ size: "lg", color: "secondary" })); // => "flex items-center py-4 px-8 bg-gray-500 text-white"
```

### `@tw-classed/react`

This is the React library. It's a wrapper around `@tw-classed/core` provides a React component creator similar to `styled-components` or `stitches.js`.

```tsx
import classed from "@tw-classed/react";

const Button = classed("button", "flex items-center", {
  variants: {
    size: {
      sm: "py-2 px-4",
      md: "py-3 px-6",
      lg: "py-4 px-8",
    },
    color: {
      primary: "bg-blue-500 text-white",
      secondary: "bg-gray-500 text-white",
    },
  },
  defaultVariants: {
    size: "md",
    color: "primary",
  },
});

const App = () => {
  return (
    <div>
      <Button>Default</Button>
      <Button size="sm">Small</Button>
      <Button size="lg" color="secondary">
        Large Secondary
      </Button>
    </div>
  );
};
```

## Down the road

There is still lots of things to do with this library before I feel confident in releasing a V1 stable release. Please don't use it in production just yet. Here is a list of future things.

* Class merger/differ (Omits classNames when a variant overrides)
* compoundVariants - Stitches inspired API to toggle variants when other variants are defined
* Typescript performance testing
* Stable `core` typescript API - currently only `react` is stable
* Improve TailwindCSS Extension class RegEx for intellisense

## Footnote

Thank you for reading this article! I hope many will test the library and provide feedback as its essential to improving. Any PR's and issues are welcome!

Here is the [GitHub](https://github.com/sannajammeh/tw-classed)

I can be reached at [My Website](https://sannajammeh.com) or through [Twitter](https://twitter.com/SannaJammeh5)