DEV Community

Brendan Carney
Brendan Carney

Posted on

How We Use Tailwind in Components

I wrote about Why We Use Tailwind at ConvertKit. This is about how we use Tailwind in our components.

The short version is that we use the tailwind classes directly in our components:

const Button = (props) => 
  <button {...props} className="px-4 py-2 bg-gray-700 text-white" />

But, we also want our components to do a little more. We want to work with a fixed set of colors, sizes, etc. to make development easier and our UI more consistent. That way, our developers can write code like this:

<Button color="red" size="lg">Save Form</Button>

instead of having to repeat classes all the time:

<Button className="bg-red text-white px-4 py-2"/>

Here's how we do that:

const DEFAULT = "border border-solid border-transparent";

const COLORS = {
  green: "text-white bg-green-400 hover:bg-green-500",
  red: "text-white bg-red-400 hover:bg-red-500"
};

const Button = ({ color, children, className, ...props }) => {
  className = [className, DEFAULT, COLORS[color]].join(" ");

  return (
    <button {...props} className={className}>
      {children}
    </button>
  );
};

This is a simplified example of our actual component that's only handling the different colors. We have a default set of classes that all buttons have (DEFAULT), then, we have an object representing the different colors (COLORS). When someone passes red as the color prop, we use the classes that match that key: COLORS["red"]. We merge all this together with the className prop that that you can also pass to our component to add additional classes if necessary.

// A red button with margin at the bottom
<Button color="red" className="mb-2"/>

We follow the same pattern for sizes, variants, and different states of our components.

How are you using Tailwind in React components?

P.S. We're hiring a few full stack engineers at ConvertKit. Learn more here convertk.it/engineer

Top comments (12)

Collapse
 
diederikvandenb profile image
Diederik van den Burger • Edited

Instead of doing this join, you could consider the classnames package on npm.

className = [className, DEFAULT, COLORS[color]].join(" ");

Also, I think you shouldn't reassign prop variables like this. Other than that: nice article!

Collapse
 
brendanrc2 profile image
Brendan Carney

Good point! We actually do use the classnames package 🙂. I left it out here to keep the example as simple as possible. Thanks for reading!

Collapse
 
730projects profile image
730. - Daaf

Hi Brendan, very nice approach this!
Do you have any ideas on how to achieve the same thing in a Vue component?

Collapse
 
brendanrc2 profile image
Brendan Carney

Thanks! I've been meaning to check out Vue, but I've actually never used it. I tried scanning the docs a bit and found this: vuejs.org/v2/guide/class-and-style.... I think the function form a couple paragraphs down could be helpful, but I'm not sure exactly what it would look like.

Collapse
 
730projects profile image
730. - Daaf

I got it to work! But could you explain: why is this approach more beneficial than for example Extracting CSS components with @apply (as explained here tailwindcss.com/docs/extracting-co...)?

Thread Thread
 
diederikvandenb profile image
Diederik van den Burger • Edited

I think you need to take in to account some of the differences between Vue and React when answering this question.

A Vue template gives you the ability to have your code and styles live in the same .vue file. The solution presented in this article is one of many ways to achieve the same goal in React.

I also believe the apply method doesn’t allow classes like “sm:p-0” because of the colon, so you’d have to be a little bit more verbose and do a media query in which you do the apply.

Correct me if I’m wrong on that last one though.

Collapse
 
charlesokwuagwu profile image
Charles

@Daaf RE: I got it to work!

Please can you share a snippet of how you got this to work in Vue, could you make it work as a light-weight functional component ?
Thanks

Collapse
 
730projects profile image
730. - Daaf

Hey Charles, I indeed got it to work.
But later I realised it's no more different than extracting components using Tailwind CSS's @apply directive. In case you really want to know, I've made a small example here.

Let me know if this is working for you!

Collapse
 
vasco3 profile image
JC • Edited

I do it very similar. Instead of colors I call them Intents. Instead of green and red I use success and error

Collapse
 
davidzkeefe profile image
David

I literally did this exact same thing over the weekend. Tailwind is the best!

Collapse
 
8brandon profile image
Brandon Roberts

How do you handle changing classes depending on the component States?

Collapse
 
gabrielmlinassi profile image
Gabriel Linassi

It's a nice approach, thanks. I'll use on my project as well.