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.
Here is what it solves:
- Simple encapsulation of class names
- Toggle-able class names via props
- Extending existing components
- 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.
- call
classed
and define what element you want to render - Add your class names
- Add any variants (Stitches developers will feel right at home)
- Render it!
Below are some examples of what can be done:
A simple component with color prop
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).
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
// 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
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:
Top comments (2)
Quick question: Does this create runtime overhead?
Very little. Its equally fast as CVA and 2x faster than stitches (fastest css in JS lib). But there is always a slight perf hit when we’re dealing with loops