TW Classed - Make reusable Tailwind components
Tags: react, tailwindcss, webdev, javascript
Published: 2022-12-09 15:00:00



Earlier last month I wrote an article titled "Im merging css-in-js and Tailwind". A lot has happened since then, I've published the `v 1.0.0` version of my library and received a ton of great feedback from the community. We are now at `v1.3.0`! It's time to give this library a proper announcement.

## Introducing TW Classed V1

Tailwind CSS and CSS-in-JS, the best of both worlds. Great DX and user experience right out of the gate. 

[Full Documentation](https://tw-classed.vercel.app)

Here is what it solves:

1. Simple encapsulation of class names
2. Toggle-able class names via props
3. Extending existing components
4. Fully typesafe all the way down to the HTML definitions

### How does it work?

If you've used Stitches or Styled Components this will feel very familiar. TW Class does not inject any styles, it servers as a class toggler and component generator.

1. call `classed` and define what element you want to render
2. Add your class names
3. Add any variants (Stitches developers will feel right at home)
4. Render it!

Below are some examples of what can be done:

#### A simple component with color prop
```tsx
import { classed } from "@tw-classed/react";
// classed("button", ...classes) is also possible
const Button = classed.button("px-4 py-2", {
  variants: {
    color: {
      primary: "bg-blue-500 text-white",
      secondary: "bg-gray-500 text-white",
    },
  },
});

() => <Button color="primary">Primary</Button>
() => <Button color="secondary">Secondary</Button>
```

#### Multi argument support

TW Classed supports an infinite number of arguments. You can pass it any combination of strings (will be set as classes), variants (classes toggled by props) or even other classed components (current component will inherit all classes and props).

```tsx
const Grid = classed.div(
  "grid gap-4", // Mobile first
  "md:grid-cols-2 md:gap-6", // Tablet
  "lg:grid-cols-3 lg:gap-8", // Desktop
  "xl:grid-cols-4" // Large desktop
);

const BlueGrid = classed(Grid, "bg-blue-500");

// Doesn't render Grid but grabs all classes and variants and injects into classed.section
const Section = classed.section("bg-blue-500", Grid)
```

#### Extending other components
```tsx
// Link.tsx
import Link from "next/link";
 
const ClassedLink = classed(Link, "text-blue-500 hover:text-blue-700");

// In your App
() => <ClassedLink href="/docs">Go to docs</ClassedLink>;

// Or by overriding the rendered element
const Anchor = classed("a", "text-blue-500 hover:text-blue-700");

// In your App
() => <Anchor as={Link} href="/docs">Go to docs</Anchor>;
```

All this and more features like `defaultVariants`, `compoundVariants`, advanced class name merging, Tailwind Extension support and a framework agnostic library is available in the [Documentation](https://tw-classed.vercel.app)

### The why?

Creating design systems with plain React components and Tailwind can be quite tricky. `CSS in JS` solved this perfectly, but many of us enjoy working with Tailwind.

Creating React components in a typesafe design system requires:

- Creating TypeScript props
- Extending the underlying element's props
- Add Types for props controlling class names
- Manually mapping the class names to certain prop values (which may or may not change...)
- Adding `forwardRef`

I therefore made sure all this is handled out of the box in `tw-classed`. It's as close to a CSS in JS library as possible, but with pure classes.

### Footnote

Thank you for reading this article! I have received great support from the community and `tw-classed` wouldn't have been as good as it is today without you guys! I always welcome any kind of feedback which can be sent here:

[Github](https://github.com/sannajammeh/tw-classed)
[Discord server](https://discord.gg/Ur2xTYj2Gr)