Setting up Tailwind With create-react-app
Tags: react, javascript, tailwindcss
Published: 2019-08-02 13:58:42

## What is Tailwind?
Tailwind is a functional CSS framework that is ergonomic to use, but low level enough to make it fully customizable. You can configure it, add plugins, and override defaults. It generates CSS class names for you so that you can use compose them throughout your project.

I've found that Tailwind lends itself particularly well to developing components in React and Vue.

---

## What does it look like?

```jsx
import React from 'react'

export default function Input(inputProps) {
  return (
    <input 
      className="px-2 py-1 text-gray-700 bg-gray-200 rounded-lg shadow-md border-2 border-gray-800 focused:border-blue-400"
      {...inputProps} 
    />
  )
}
```

What do all of those classes mean? Most of the classes should be pretty self explanatory. The `px-2` and `py-1` are horizontal (x), and vertical (y) padding respectively. The `2` and `1` refer to the sizing. 

By default Tailwind generates a set of sizes for you that you can customize. Sizing 1 starts at `0.25rem` and the sizing goes up by `0.25rem` each step.

The class naming follows pretty easy to understand conventions so once you start learning some you will understand how to use most. For instance to set a margin vertical margin of 2 rem you would use the class name `my-8`. `m` because you are setting margin, `y` because you want to set only the vertical axis margin, and `8` because you want 2 rem and the sizing is 4 per rem.

Things that can accept a color value like text, border, or background have their prefix `text`, `border` and `bg`, followed by the color name `text-gray`, `border-gray` or `bg-gray` and then a value from 100-900 that jumps by 100. So `text-gray-700` will make the text a fairly dark gray, and `bg-gray-200` will give the background a fairly light gray color.

The `focused:border-blue-400` class applies a blue 400 color to the border when the focused pseudo class is active for the element.

`rounded` has a number of suffixes to affect the class like `sm`, `lg`, and `full` with the default being a medium rounded border if there isn't a suffix. There is even the ability to change any corner individually.

`shadow` is similar to `rounded` but with the default being small with no suffix, and sizing all the way to `2xl`. Additional modifiers that make sense for a box shadow are also available like `inner` or `outline`.

---

## Why would you use it?

When you get into the flow it's like writing regular CSS with shorthands except you don't have to do it in a separate file, you don't have to come up with a bunch of class names, and you don't have to possibly update two files every time you change the styles for a single element.

It  makes your code easier to delete. We'll touch on this more later, but traditional CSS is append only, which means it is really hard to know when you are okay to delete some styles. 

Component based styling, which you can absolutely do with Tailwind, allows you to delete the styles along with the component when you no longer need it.

Tailwind is also totally and completely extendable. Want to add different colors, or change the ones included with Tailwind? You totally can and the API to do so is pretty well [documented](https://tailwindcss.com/docs/configuration) and easy to follow.

## How do we set up create-react-app to use Tailwind?

Let's set up our project by scaffolding a new react app with `create-react-app`. If you don't have it installed you can use npx.

```sh
npx create-react-app setting-up-tailwind && cd setting-up-tailwind
```
Now we need to install some dev dependencies.

```sh
yarn add -D tailwindcss autoprefixer postcss-cli
```
In the root of the project create a `postcss.config.js` file and open it up in your favorite editor.

```javascript
module.exports = {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
  ]
}
```

If you're interested in finding out more about PostCSS check out the [Github](https://github.com/postcss/postcss)

Autoprefixer is recommended to install alongside Tailwind, because autoprefixer automatically tracks caniuse.com to see which CSS properties still need to be prefixed, and out of the box Tailwind does not provide any vendor prefixing.

Now we should initialize Tailwind. This will create a tailwind.config.js file in the root of our project with a default configuration. This step is optional, but I usually do this when setting up a Tailwind project so that I can customize things later without having to come back.

```sh
npx tailwind init
```

If you open it up it looks pretty barren right now. Maybe in a different post I'll go over adding plugins, or customizing Tailwind.

```javascript
// tailwind.config.js
module.exports = {
  theme: {
    extend: {}
  },
  variants: {},
  plugins: []
}

```

We also need to create an input CSS file for PostCSS to process with Tailwind. I usually call this `tailwind.css` and add it to the `src` folder in my React projects, but you can name it whatever, and place it in any place that makes sense to you.

```css
/* src/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
``` 

These are Tailwind directives that add the three main parts of core Tailwind. You can make your bundle smaller by omitting one or multiple if you don't need them, but to get the most from Tailwind you will probably end up using at least some classes from each.

When Tailwind (the first plugin in PostCSS) sees these directives it will replace each `@tailwind <name>` with some CSS.

To make it easy on ourselves in the future case where we might be changing the `tailwind.config.js` we should add a few scripts to our `package.json` file. Add the following three scripts to the scripts object.

```js
// package.json
{
  //...
  "scripts": {
    //... place these after the four scripts created by CRA
    "build:styles": "postcss src/tailwind.css -o src/styles.css", 
    "prebuild": "yarn build:styles",
    "prestart": "yarn build:styles"
  }
}
```

Or if you use npm change `yarn` to `npm run`

```js
{
  //...
  "scripts": {
    //... place these after the four scripts created by CRA
    "build:styles": "postcss src/tailwind.css -o src/styles.css",
    "prebuild": "npm run build:styles",
    "prestart": "npm run build:styles"
  }
}
```

## Building our React component

Let's delete some of the unnecessary stuff that create-react-app makes for us.

```sh
rm src/App.test.js src/App.css src/index.css src/logo.svg
```

Open up `src/index.js` and make the following changes.

```jsx
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './styles.css' // <- change './index.css' to './styles.css'
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
```

Now open up `src/App.js`, delete the whole thing and start from scratch.

```jsx
// src/App.js
import React from "react";
import Button from "./components/button";

function App() {
  return (
    <div className="flex flex-col w-3/4 mx-auto my-12 items-center">
      <h1>Super cool page</h1>
      <Button onClick={() => console.log("I was clicked")}>
        I am a button
      </Button>
    </div>
  );
}

export default App;
```

Let's create a simple button component, this will be a small wrapper around a normal button, but will contain some styles. I'm making this component in a `components` directory inside of `src`, but you can put the component wherever you want.

```jsx
// src/components/button.js
import React from "react";

export default function Button({ children, ...buttonProps }) {
  return (
    <button
      className="px-2 py-1 rounded-lg bg-green-400 text-green-800 text-xl font-light uppercase shadow-md hover:shadow-lg"
      {...buttonProps}
    >
      {children}
    </button>
  );
}
```

If you run yarn start now you should see that PostCSS is processing our styles for us, and then you should see something like this.

![](https://thepracticaldev.s3.amazonaws.com/i/ofjwq1nujeugmrrdj884.png)

### Such beauty. It is almost too much to behold!

---

## Checking our app out in production

So our app is looking great now and we are ready to send it off into the world, but first we need to build for production. 

```sh
yarn build
```

Now to check our production build, we can use a tool like `serve`. Either install it globally, `yarn global add serve` or you can use npx.

If you installed globally you'll use
```sh
serve -s build
```
or if you want to use npx
```sh
npx serve -s build
```

Sweet! Our page looks pretty rad if I do say so myself. Now let's just open up the developer tools in our browser, click on the network tab, refresh the page and see how slim our sleek new CSS is...


![](https://thepracticaldev.s3.amazonaws.com/i/okekz472vdgw6ymemptw.gif)

Look at the size of the CSS bundle. 350KB... Yikes! Why is it so big!? 

![](https://thepracticaldev.s3.amazonaws.com/i/cul3usx78uu0gumn4sk4.gif)


Well Tailwind generates classes. A lot of classes. The stylesheet that it generates is over 3000 lines long. But we are only using a fraction of those classes right now so what can we do?

## Slimming Our Build

There is a utility called PurgeCSS which will parse any files that match the given file globs for the usage of the selectors in your CSS. If a selector isn't present in any of the matched files, then it rips those styles out of the CSS, ultimately slimming the build. 

There is a PostCSS plugin for PurgeCSS so we can just install our new dependency, and add a little bit more set up to `postcss.config.js`.

```sh
yarn add -D @fullhuman/postcss-purgecss
```

Open up your `postcss.config.js` file and make some additions. The following set up is taken [directly from the Tailwind docs](https://tailwindcss.com/docs/controlling-file-size/#setting-up-purgecss).

```javascript
// postcss.config.js
const purgecss = require('@fullhuman/postcss-purgecss')({

  // Specify the paths to all of the template files in your project 
  content: [
    './src/**/*.js',
    './public/index.html',
  ],

  // Include any special characters you're using in this regular expression
  defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
})

module.exports = {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
    ...process.env.NODE_ENV === 'production'
      ? [purgecss]
      : []
  ]
}
```

The content property in the PurgeCSS plugin takes an array of file globs that it should check for the inclusion of CSS selectors. In a create-react-app project we want it to check all of our React components so we pass `./src/**/*.js` which means check any nested folders inside of src for any file with an extension of `.js`. We also want it to look at our `./public/index.html` file because Tailwind uses Normalize, and without having it check the projects HTML page, it will gut a lot of the Normalize rules that we want it to include. 

There are some pitfalls with PurgeCSS, like it won't actually render your components to check dynamic class usage, so you want to avoid partial class names in dynamic renders and instead stick to full class names.

```jsx
import React from 'react'

// DO NOT DO THIS
function Button({ color, children }) {
  return <button className={`text-${color}`}>{children}</button>
}

const App = () => (
  <Button color="red-300">Do not click me</Button>
)

///////////////////////////////////
// Instead do this!

function Button({ color, children }) {
  return <button className={`${color}`}>{children}</button>
}

const App = () => (
  <Button color="text-red-300">Do not click me</Button>
)
```

The other thing that we need to do is make a slight modification to one of our scripts in `package.json`. The addition of `NODE_ENV=production` to our `prebuild` script will set the environment variable for Webpack which create-react-app uses under the hood, and will trigger the PostCSS cli to use PurgeCSS in the building of our styles.

```js
// package.json
{
  "scripts": {
  //...
    "prebuild": "NODE_ENV=production yarn build:styles"
  }
}
```

Now let's build for production, serve our app, open up the dev tools and check out our network tab again.

```sh
yarn build && serve -s build
```

![](https://thepracticaldev.s3.amazonaws.com/i/0wx5pm30wn1dltdrrtoi.gif)

Much better!

If you want to further slim the build there is great documentation on [how to control the size](https://tailwindcss.com/docs/controlling-file-size/) of Tailwind.

---

So now you know how to set up Tailwind in your create-react-app projects and how to get some decent production wins with PurgeCSS + PostCSS. Let me know if you any questions in the comments, or if you enjoyed this article.