Simple Trick to Clean Up Tailwind CSS in React

Last modified
October 13, 2020
Time to read
1 min read

Photo by Anisur Rahman

Table of Contents

Problem

A pain point with using utility-first CSS framework like Tailwind CSS is that you invetibaly end up with components such as these.

<a
  href="#"
  class="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-primaryBold bg-neutralBg hover:text-primary focus:outline-none focus:border-primaryBgSofter focus:shadow-outline-indigo transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10">
  Live demo
</a>

Consider the following:

What are the ways we would write Tailwind CSS utility classes?

It could be a string.

function Button() {
  return (
    <button className="px-4 py-2 bg-blue-500 hover:bg-blue-600 shadow-md ...">
      Click
    </button>
  );
}

To include JavaScript, we could write a template literal.

function Button({ color }) {
  return (
    <button
      className={`${whateverJavaScript(color)} 
    px-4 py-2
    bg-blue-500 hover:bg-blue-600
    shadow-md
    ...
    `}
    >
      Click
    </button>
  );
}

The problem with template literals is in the name itself.

They are literal.

Formatters and linters such as Prettier and ESLint make no attempt to format the utility classes written in template literals, leading to files with sloppy indentation.

Solution

The solution is inspired by code in tailwindlabs/tailwindui-react.

The solution is a function.

JavaScript:

// tailwind.js
export function tw(...classes) {
  return classes.filter(Boolean).join(' ');
}

TypeScript:

// tailwind.ts
export function tw(...classes: (false | null | undefined | string)[]): string {
  return classes.filter(Boolean).join(' ');
}

We could optionally name this function classNames as the original author Robin Malfait did in tailwindui-react.

I chose tw to give brevity for the writer and context for the reader.

Now we can cleanly span our classes over many lines.

Moreover, now the formatter can easily format our files.

// @components/Hero.tsx
import Logo from '@assets/logo.svg';
import tw from '@utils/tailwind';

function Hero() {
  return (
    <Logo
      className={tw(
        'relative',
        'w-full h-auto',
        'mt-2 mb-4',
        'text-blue-600 fill-current'
      )}
    />
  );
}

Group together similar classes, such as

  • position
  • spacing
  • sizing
  • color

When in doubt, group things the way Tailwind groups things on their website.

import Logo from '@assets/logo.svg';
import tw from '@utils/tailwind';

function Hero() {
  return (
    <Logo
      className={tw(
        'absolute top-2 left-2', // position
        'mt-2 mb-4', // spacing
        'w-full h-auto', // sizing
        'text-blue-600 fill-current' // color
      )}
    />
  );
}

Easily include JavaScript sources.

import Logo from '@assets/logo.svg';
import tw from '@utils/tailwind';
import globalStyles from '@styles';
function Hero() {
  return (
    <Logo
      className={tw(
        'absolute top-2 left-2', // position
        'mt-2 mb-4', // spacing
        'w-full h-auto', // size
        'text-blue-600 fill-current', // color
        globalStyles.transitions      )}
    />
  );
}

In addition, we could use a plugin like Headwind to also alphabetize the classes.

I don't care that much to have my classes alphabetized, and I've found it to make for a worse DX.

Hope this helps you clean up Tailwind CSS in your own React projects.

What are some of your favorite Tailwind CSS tricks?

Let me know on Twitter! 馃憢

Last modified
October 13, 2020
Time to read
1 min read

Get the latest articles
Sign up for the newsletter

I will not send you spam. Unsubscribe at any time.

Was this helpful?