6 Tips for Tailwind CSS Development (with resources!)
Tags: tailwindcss, webdev, css
Published: 2020-12-29 15:29:10

---
title: 6 Tips for Tailwind CSS Development (with resources!)
published: true
description: Learn neat tricks and resources to speed up your development with Tailwind CSS
tags: TailwindCSS, WebDev, CSS
cover_image: https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608880551/6-tips-for-tailwind-css-development-with-resources/Group_1_bu9bsm.png
---

In my [previous post](https://dev.to/joserfelix/why-use-tailwind-css-for-your-next-project-39hp), I gave a myriad of reasons why Tailwind CSS is a great option for new and existing projects. When first starting out, it can be daunting to learn every utility class name and know what will fit the situation best in the present and future. This is why, in this post, I will give you tips that I have learned throughout my journey learning Tailwind. These are not rules, but I've found they have made my development easier and more readable. 

## 1. Use 'clsx' to Join Classes

Let's start with something that is highly recommended for every project: using `clsx` for joining class names. [Clsx](https://github.com/lukeed/clsx) is a simple JavaScript utility for conditionally joining classes together. It makes our lives easier by giving us syntactic sugar to handle complex styles for CSS solutions like CSS modules, or Tailwind CSS. 

> 💡 This library is the same as [Classnames](https://github.com/JedWatson/classnames) but has a smaller bundle size and better [performance](https://github.com/lukeed/clsx/tree/master/bench).

Its syntax varies between the developer preference and use case. Its syntax can range from arrays to objects. Let's look at all the possibilities: 

```jsx
// EXTRACTED FROM https://github.com/lukeed/clsx 
import clsx from 'clsx';

// Strings (variadic)
clsx('foo', true && 'bar', 'baz');
//=> 'foo bar baz'

// Objects
clsx({ foo:true, bar:false, baz:isTrue() });
//=> 'foo baz'

// Objects (variadic)
clsx({ foo:true }, { bar:false }, null, { '--foobar':'hello' });
//=> 'foo --foobar'

// Arrays
clsx(['foo', 0, false, 'bar']);
//=> 'foo bar'

// Arrays (variadic)
clsx(['foo'], ['', 0, false, 'bar'], [['baz', [['hello'], 'there']]]);
//=> 'foo bar baz hello there'

// Kitchen sink (with nesting)
clsx('foo', [1 && 'bar', { baz:false, bat:null }, ['hello', ['world']]], 'cya');
//=> 'foo bar hello world cya'
```

This diversity is very powerful and useful when handling complex UIs.

I have chosen two syntaxes for writing Tailwind CSS classes: object notation for handling conditionals and comma-separated values for prefixes. 

I first started using the basic string inline evaluation, but soon realized that my classes were ending up crammed. Take a look at this example:

```jsx
clsx('classes', cond1 && 'classes classes1 classes2', cond2 && cond3 && cond4 && '...') 
```

This is considered one of the drawbacks of Tailwind. It can quickly become unreadable and unpleasant to maintain. So I chose JavaScript objects to handle conditional class names. 

No matter how many conditions there are, it is easier to read and keep track of. Let's look at the same above code, but in the new syntax: 

```jsx
clsx('classes', {
	'classes classes1 classes2': cond1,
	'...': cond2 && cond3 && cond4
})
```

Immediately one can notice how easier it is to read, and one can avoid the berated long list of class names.

Furthermore, When working with prefixes like responsive class names and dark mode, we would have: 

```html
<div class="block bg-white text-left space-y-1 py-2 w-full sm:w-1/2 sm:space-y-0 md:w-1/3 md:space-x-6 dark:bg-gray-700" />
```

My solution to this type of long class names is using comma-separated values in clsx. Like this: 

```jsx
<div
  class={clsx(
    'block bg-white text-left space-y-1 py-2 w-full',
    'sm:w-1/2 sm:space-y-0',
    'md:w-1/3 md:space-x-6',
    'dark:bg-gray-700',
  )}
/>
```

If needed and you use a code formatter like Prettier, it will send each value to a new line. This as you may see makes classes easier to read and modify in the future. 

> 💡If there are few class names like 4 or 5 then I use a plain string since there are no readability improvements otherwise.

You may be asking what about the performance loss by using a JavaScript library like `clsx`. It will affect performance but in a negligible way. The library is so [small](https://bundlephobia.com/result?p=clsx@1.1.1) (311 bytes) and fast that users wouldn't notice any performance difference during runtime. 

## 2. Separate Into Small Components

Tailwind's inline classes allow elements to not rely on the context of implementation. This means styles can be portable — movable through any context without losing meaning. 

We should take advantage of it and create as many components as we can. This makes our code more readable by giving it a better composition, and it is easier to maintain in the long run. 

Take for example the following snippet: 

```jsx
const Post = ({
  content,
  frontmatter,
  slug,
  nextPost,
  previousPost,
}: Props) => (
    <div className="px-10 pt-40 pb-24 space-y-40 md:pt-48">      
      <article className="prose prose-lg xl:prose-2xl">
        <header>
          <h1 className="text-center">
            {frontmatter.title}
          </h1>
          <Image
            className="rounded-lg"
            src={frontmatter.cover_image}
            alt="cover image"
          />
        </header>
        <ReactMarkdown
          escapeHtml={false}
          source={content}
          renderers={{
            code: CodeBlock,
            inlineCode: InlineCode,
            image: InlineImage,
          }}
        />
      </article>
      <hr className="max-w-4xl mx-auto text-center border-black mb-20"/>     
      <section className="flex flex-col items-center mx-auto space-y-20">
        <header>
          <h1 className="text-5xl font-bold">You may also like</h1>
        </header>
        <div className="flex flex-col space-y-10 sm:flex-row sm:space-y-0 sm:space-x-20">
          {previousPost && <RecommendedPostCard post={previousPost} />}
          {nextPost && <RecommendedPostCard post={nextPost} />}
        </div>
      </section>      
      <hr className="max-w-4xl mx-auto text-center bg-black border-black" />
      <Subscribe className="w-full p-0 mx-auto" />
    </div>
);
```

When you read this the first time, you may not even know what each element is doing, aside from those that have specific names already like `ReactMarkdown` and `Image`.

Since our styles do not rely on the context, we can create new smaller components that will make it a lot easier to reason about our code.

```jsx
const Post = ({
  content,
  frontmatter,
  slug,
  nextPost,
  previousPost,
}) => (
    <div className="px-10 pt-40 pb-24 space-y-40 md:pt-48">      
      <article className="prose prose-lg xl:prose-2xl">
        <PostHeader frontmatter={frontmatter} />
        <ReactMarkdown
          escapeHtml={false}
          source={content}
          renderers={{
            code: CodeBlock,
            inlineCode: InlineCode,
            image: InlineImage,
          }}
        />
      </article>
      <Divider className="mb-20" />

      <RecommendedPosts previousPost={previousPost} nextPost={nextPost} />

      <Divider className="bg-black" />
      <Subscribe
        vertical
        showLottie={false}
        className="w-full p-0 mx-auto"
      />
    </div>
);

const PostHeader = ({ frontmatter }) => (
  <header>
    <h1 className="text-center">
      {frontmatter.title}
    </h1>
    <Image
      className="rounded-lg"
      src={frontmatter.cover_image}
      alt="cover image"
    />
  </header>
);

const RecommendedPosts = ({
  previousPost,
  nextPost,
}) => (
  <section className="flex flex-col items-center mx-auto space-y-20">
    <header>
      <h1 className="text-5xl font-bold">You may also like</h1>
    </header>
    <div className="flex flex-col space-y-10 sm:flex-row sm:space-y-0 sm:space-x-20">
      {previousPost && <RecommendedPostCard post={previousPost} />}
      {nextPost && <RecommendedPostCard post={nextPost} />}
    </div>
  </section>
);

const Divider: React.FC<DividerProps> = ({ className, ...other }) => (
  <hr className={clsx("max-w-4xl mx-auto text-center border-black", className)} {...other} />
);
```

By separating these components, we can be sure that our code will be easily read and have better composition. 

Furthermore, modifying one of these components will be effortless in the future. Each one has a purpose and is isolated from extraneous logic. This means that developers can be sure they are modifying a specific element and are not affecting other features. 

As a rule of thumb, every piece of elements that have constituted a specific role in the website can be separated into a component. This includes sections, navigation, cards, buttons, and even the page itself. 

This does not mean that everything should be put in a component. It is best to look for those that will improve readability. 

As long as you can't read your code like a normal book or article, it probably means you can benefit from the separation. While this is highly subjective, a way to objectively identify it is by looking for duplicate class names and their role on the site. 

For example, The two `<hr />` in the non-refactored Page component have nearly identical classes. Their only difference was an `mb-20` class name in the first tag and `bg-black` in the second. 

```jsx
<hr className="max-w-4xl mx-auto text-center border-black mb-20"/>
// ...
<hr className="max-w-4xl mx-auto text-center border-black bg-black" />
```

So, to avoid repetition we created a component and sent the `className` prop to extend the classes.

```jsx
const Divider: React.FC<DividerProps> = ({ className, ...other }) => (
  <hr className={clsx("max-w-4xl mx-auto text-center border-black", className)} {...other} />
);
```

## 3. Get VS Code Extensions

Since Tailwind CSS is so predictable, it opens a world of possibilities for extensions that improve development productivity and lower the learning curve. 

Here are my five favorites: 

### Tailwind CSS IntelliSense

[Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) improves Tailwind development experience greatly by providing advanced features like autocomplete, syntax highlighting, and linting. 

I believe this is a must-have. It's very useful for learning Tailwind and remembering class names. 

Further, it can read your `tailwind.config.js` and adapt to its values. This is very helpful when adding color, or an official plugin. 

![Tailwind IntelliSense in action](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608530326/6-tips-for-tailwind-css-development-with-resources/Untitled_optazd.png)

### Refactor CSS

[Refactor CSS](https://marketplace.visualstudio.com/items?itemName=urbantrout.refactor-css) is a neat extension that lets you identify recurring CSS class names in markup. This is an excellent indicator for knowing when to create a component. 

![Refactor CSS showing duplicate classes.](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608530386/6-tips-for-tailwind-css-development-with-resources/Untitled_1_t66ki4.png)

### Headwind

This one is huge. [Headwind](https://marketplace.visualstudio.com/items?itemName=heybourn.headwind) is an opinionated class sorter for Tailwind CSS. It enforces a specific order of classes. It creates a seamless organization in your components that is noticeable right away. In my opinion, it's a must-have. 

![Headwing sorting classes](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608530620/6-tips-for-tailwind-css-development-with-resources/ezgif.com-gif-maker_ughrmy.gif)

> 💡 Recently, a new [prettier plugin](https://github.com/Acidic9/prettier-plugin-tailwind) came out for sorting Tailwind classes. It is best to keep an eye on it and try it if you can. It is perfect for enforcing class order for teammates that use other editors or don't have the extension.

### Tailwind Shades

Sometimes it is very useful to generate different shades for a specific HEX color. [Tailwind Shades](https://marketplace.visualstudio.com/items?itemName=bourhaouta.tailwindshades) allows you to do so quickly and right within your editor.  

![Tailwind Shades generating shades for a specific hex](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608530800/6-tips-for-tailwind-css-development-with-resources/ezgif.com-gif-maker_1_qv4gpo.gif)

### Tailwind Docs

Tailwind docs is a tool that makes Tailwind CSS documentation available on the command palette. This is very useful when one needs to remember a concept or is learning the framework. It also makes you avoid having to search on Google for the documentation link.  

![Tailwind Docs searching and opening Tailwind CSS documenation](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608530840/6-tips-for-tailwind-css-development-with-resources/preview_aaml0q.gif)

## 4. Rely on Plugins

It is no surprise that Tailwind CSS is [extensible](https://tailwindcss.com/docs/plugins). Plugins help developers register new styles for Tailwind CSS through JavaScript. 

One could go down a rabbit hole on what it is possible through plugins. But, in short, they are useful for teams looking to share their styles through the organization or developer who wish to generate class names for complex use cases like animations. 

Not only can plugins be created for personal or organizational reasons, but also the community creates very useful plugins that make the developer's life a lot easier. 

Here are some of the best plugins you can use for speeding up your development: 

### Tailwind Forms

[Tailwind Forms](https://github.com/tailwindlabs/tailwindcss-forms) is a plugin developed by the official team of Tailwind CSS. It provides a styles reset for form elements, making it easier to override its styles. This one is a must if one is creating custom forms. 

![Simple form showcasing Tailwind forms styles](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608530909/6-tips-for-tailwind-css-development-with-resources/Untitled_2_s4dsub.png)

### Tailwind Typography

[Tailwind Typography](https://github.com/tailwindlabs/tailwindcss-typography) is another high-quality plugin developed by the Tailwind team. It provides a set of classes that add typographic defaults as [Typography.js](https://kyleamathews.github.io/typography.js/) does. 

It's necessary to style any HTML elements one can't control like, for example, those generated from Markdown. 

This one is a must for developing websites that consume a CMS and generate elements through a parser. 

![Blog post with Tailwind Typography styles](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608530943/6-tips-for-tailwind-css-development-with-resources/Untitled_3_zcxauj.png)

> 💡 I use this plugin on my [nextjs-starter-blog template](https://github.com/JoseRFelix/nextjs-starter-blog). Check it out if you want or need to start a blog!

### Tailwind CSS Debug Screens

[Tailwind CSS Debug Screens](https://github.com/jorenvanhee/tailwindcss-debug-screens) is a small neat utility that shows the currently active responsive breakpoint. It is very useful when making layouts since one does not have to go to development tools to see current dimensions. 

![Tailwind CSS Debug Screens showing current screen breakpoint](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608530965/6-tips-for-tailwind-css-development-with-resources/Untitled_4_cwkirm.png)

### Tailwind CSS Theming

[Tailwind CSS Theming](https://github.com/innocenzi/tailwindcss-theming) is a plugin that solves the problem of multiple themes within Tailwind. It's perfect for applications that rely on [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) to change themes dynamically. I highly recommend this plugin if your project has more than one theme, or need a quick solution for handling themes.  

Its main benefit is its readable and straightforward syntax. 

```jsx
// Extracted from: 
// https://github.com/innocenzi/tailwindcss-theming/blob/master/docs/quick-start.md
// theme.config.js

const { ThemeManager, Theme } = require('tailwindcss-theming/api');

const base = new Theme()
  .addColors({
    brand: '#44b3ac',             // Your brand color
    'on-brand': '#ffffff',        // For everything that goes on your brand color
    background: '#f7fafc',        // A background color
    'on-background': '#1a202c'    // For everything that goes on your background color
  });

const dark = new Theme()
  .addColors({
    brand: '#44b3ac',             // Your brand color
    'on-brand': '#ffffff',        // For everything that goes on your brand color
    background: '#1c1e26',        // A background color
    'on-background': '#d5d8da'    // For everything that goes on your background color
  });

module.exports = new ThemeManager()
  .setDefaultTheme(base)          // Sets the `base` theme as the default theme.
  .setDefaultDarkTheme(dark);     // Sets the `dark` theme as the default theme for users that prefer the `dark` scheme.
```

## 5. Use Pre-Built Components

Since separating into small components is so easy in Tailwind, it is no surprise that its community has created a lot of beautiful component abstractions with it. There are even websites dedicated to this. 

Here are some websites or libraries you can use to get pre-built components: 

### Tailwindcomponents

[Tailwindcomponents](https://tailwindcomponents.com/) is a free repository of open source components created by the community. This website is a gem because one can find pretty much anything one needs. 

Everyone can submit their components and help other developers in building or learning layouts with Tailwind.  Even Adam Wathan, the creator of Tailwind, submits layouts! 

![Tailwind Components landing page](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608531118/6-tips-for-tailwind-css-development-with-resources/Untitled_5_xlmudn.png)

### Tailwind Toolbox

[Tailwind Toolbox](https://www.tailwindtoolbox.com/) is similar Tailwindcomponents. It has many useful components and additional templates, plugins, tools, and generators. However, it only allows users to suggest resources and not upload their own. This means that content will no be as diverse and abundant as Tailwindcomponents, but it's very useful nonetheless. 

![Tailwind Components landing page](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608531139/6-tips-for-tailwind-css-development-with-resources/Untitled_6_kl9kbt.png)

### Tailwind UI

[Tailwind UI](https://tailwindui.com/) is a beautiful UI library created by Adam Wathan, and Steve Schoger, author of [Refactoring UI](https://refactoringui.com/). It contains a lot of components, albeit mostly behind a paywall. Nevertheless, the free samples are very high quality and can be useful to give an idea of how to implement a UI. 

![Tailwind UI landing page](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608531157/6-tips-for-tailwind-css-development-with-resources/Untitled_7_gqbb5j.png)

### Tailblocks

[Tailblocks](https://mertjf.github.io/tailblocks/) is a website that contains common layouts done with Tailwind CSS. They are very useful for kicking off a website quickly. 

![Tailblocks website](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608531170/6-tips-for-tailwind-css-development-with-resources/Untitled_8_wvyuqy.png)

### Gust UI

[Gust UI](https://www.gustui.com/) is a very simple component library built with Tailwind. I recommend this site if you need to get some quick React logic for common components like Sliders, Toggles, etc. 

![Gust UI website](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608531193/6-tips-for-tailwind-css-development-with-resources/Untitled_9_ueqcsv.png)

### Meraki UI

[Meraki UI](https://merakiui.com/) is a Tailwind component library similar to Tailwind UI. It features common layouts and components for common use cases like authentication, navigation, footer, etc. It is worth checking out, especially since it's completely free. 

![Meraki UI landing page](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608531217/6-tips-for-tailwind-css-development-with-resources/Untitled_10_w9iedd.png)

### Reach UI

[Reach UI](https://reach.tech/) is a lifesaver for developers looking to create an accessible design system without dealing with the hassle of creating each component by hand. While these components are not made with Tailwind, they are open to being styled by it because of its granularity. 

Its only disadvantage is that its styles must be overridden through an external stylesheet or by setting [global important](https://tailwindcss.com/docs/configuration#important) in Tailwind's config. Nevertheless, these can save a lot of time.  

![Reach UI landing page](https://res.cloudinary.com/dmq9pzw0o/image/upload/v1608531234/6-tips-for-tailwind-css-development-with-resources/Untitled_11_nrxwwu.png)

## 6. Use Other Styling Solutions

While this may seem counterproductive given how Tailwind CSS is a solution itself, using another one like CSS Modules or Styled Components is recommend to handle the heavy lifting. 90% of the time you should be using Tailwind, but Any complex animation or new property is better handled through the former.

For example, let's say we want to set a `max-width` for a special component for a specific blog post. We wouldn't like to create a Tailwind class just for one use case, and inline objects may be off the charts because of preference. 

Paring up CSS Modules and Tailwind can solve this conundrum.  Since one can write Tailwind classes right alongside CSS properties. This makes it extremely powerful and makes stylesheets simpler and easier to maintain. 

```jsx
.root {
  @apply h-full bg-primary mx-auto transition-colors duration-150;

  max-width: 590px;
} 

// Called in our code as:
import s from "./styles.module.css"

<section className={s.root}></section> 
```

Another popular way of pairing up Tailwind is through a CSS-in-JS library like Styled Components. Recently, a library called [twin.macro](https://github.com/ben-rogerson/twin.macro) has received a lot of hype between developers. It allows developers to integrate Tailwind on an existing codebase with a CSS-in-JS library. This means it has all the benefits of CSS-in-JS: low build times, Javascript integration, etc. Its syntax looks like this: 

```jsx
import tw, { styled } from 'twin.macro'

const Input = styled.input`
  color: purple;
  ${tw`border rounded`}
`

const Component = () => <Input />
```

Check it out if you love CSS-in-JS and like to start having some of the benefits of Tailwind CSS. 

## Conclusion

Tailwind is an amazing CSS framework, and I expect to keep using it in the foreseeable future. By using these tips, I've found that my codebases are easy to read and seamless to maintain. I hope these were useful to you. If there is any tip or resource you think is relevant for this post, please leave it in the comments down below.  

For more up-to-date web development content, follow me on [Twitter](https://twitter.com/Jose_R_Felix), and [Dev.to](https://dev.to/jfelx)! Thanks for reading! 😎

- - -

Did you know I have a newsletter? 📬

If you want to get notified when I publish new blog posts and receive **awesome weekly resources** to stay ahead in web development, head over to <https://jfelix.info/newsletter>.