Using Tailwind CSS with Create React App

By Dave Ceddia

I’ve been hearing a lot about Tailwind CSS lately and I wanted to give it a try, but I wanted to combine Tailwind with Create React App. In this post I’ll show you how to use Create React App with Tailwind CSS in just a couple quick minutes.

I’ll show two versions: a Basic one that has the most minimal setup, and a Production version that will set things up for an optimized workflow and a smaller production build.

Here’s how to integrate Tailwind with CRA, without ejecting. It’ll work like this:

  • We’ll install a tool to do the build
  • A new build step will call our tool and to generate the CSS to use Tailwind
  • We import the generated CSS file into our React app

What’s Tailwind CSS?

Tailwind is a low-level CSS framework created by Adam Wathan. Their site calls it “A utility-first CSS framework for rapidly building custom designs.”

The idea behind Tailwind is that it gives you a bunch of utility classes, like text-lg (for a large-ish font size) or mx-auto as a shorthand for auto margins in the X direction, useful for centering something horizontally (short for margin-left: auto; margin-right: auto;).

You apply these utility classes directly to your HTML or JSX elements (via the className prop if you’re using React).

Not everyone loves this idea. But some people absolutely do love Tailwind and talk about how productive it has made them. I think it’s worth a try.

(If the idea of adding such low-level classes to your HTML bothers you, check out In Defense of Utility First CSS by Sarah Dayan and have a look at the screencast tutorials that Adam created. They might change your mind.)

Start With a React project

We’ll be modifying a Create React App (CRA) project, so create a new one or use one you already have. The steps after this will work fine with an existing project.

create-react-app demo

Set Up the Build

I’ve got two versions for you. Basic and Production.

Choose Basic if you just want to try out Tailwind with React, don’t plan on deploying this app, and want the most minimal possible setup. It’ll require a dev server restart any time you change the tailwind.css file, but if you’re doing things the Tailwind Way (adding classes to elements instead of writing CSS), you won’t really be changing that file anyway.

Choose Production if you want something you can deploy. This incorporates PurgeCSS to make sure your production builds are as tiny as possible, and a live rebuild that watches for changes. The tradeoff is more configuration up front, but it’s still just a few packages and lines to copy into place.

Setup a Basic Tailwind + CRA Build

1. Install Tailwind

Tailwind comes with its own CLI for doing a build, so we can just install the tailwindcss package.

npm install tailwindcss

2. Add Tailwind to the Build

To avoid ejecting from Create React App’s build system we’re going to insert a step that builds Tailwind before the existing start and build scripts.

Open package.json in the CRA project, add a script called build:tailwind and two more called prestart and prebuild.

(if you haven’t modified your scripts, you should be able to copy/paste this verbatim)

"scripts": {
  "build:tailwind": "tailwindcss build src/tailwind.css -o src/tailwind.generated.css",
  "prestart": "npm run build:tailwind",
  "prebuild": "npm run build:tailwind",
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject"
}

The build:tailwind script will compile our src/tailwind.css file, and output src/tailwind.generated.css – which our app will then import.

We’re effectively saying “build Tailwind before starting up dev mode” and “build Tailwind before building the React app for production”.

(Note: The script name build:tailwind isn’t special. You could call it build:css or awesomeness or happydays if you wanted.)

NPM supports pre- and post- scripts

Fun fact: Scripts that start with the word “pre” are special to NPM (and Yarn). They automatically run before the named script.

Here, prestart will run before the start script. When you run npm start, NPM will run both automatically.

The prefix “post” will do the same kind of thing, but will run after the named script. (e.g. postbuild would run after build is finished)

A One-Time Build

This setup will only build the CSS once, at startup. It will not watch for changes.

If you change src/tailwind.css you’ll have to restart the development server. If you need automatic rebuilds, check out the Production setup below.

3. Set up the Tailwind source CSS file

(this step is the same as in the Production setup)

You probably noticed that our build step refers to a src/tailwind.css file. Create that now, and paste this in:

@tailwind base;
@tailwind components;
@tailwind utilities;

The Tailwind PostCSS plugin will replace these @tailwind directives with Tailwind’s generated CSS and write it out to src/tailwind.generated.css (that name is decided by the build:tailwind script we added to package.json).

4. Import the Generated CSS File

(this step is the same as in the Production setup)

At the top of your index.js file, import the tailwind.generated.css file that’s being generated by Tailwind.

Then we can try out a few Tailwind classes to make sure it works.

import React from 'react';
import ReactDOM from 'react-dom';
import './tailwind.generated.css';

const App = () => (
  <div className="max-w-md mx-auto flex p-6 bg-gray-100 mt-10 rounded-lg shadow-xl">
    <div className="ml-6 pt-1">
      <h1 className="text-2xl text-blue-700 leading-tight">
        Tailwind and Create React App
      </h1>
      <p className="text-base text-gray-700 leading-normal">
        Building apps together
      </p>
    </div>
  </div>
);

ReactDOM.render(<App />, document.querySelector('#root'));

Start up the development server as usual with npm start.

That’s all there is to it!

Where to Make Changes

Don’t change tailwind.generated.css since your changes will be wiped out the next time you start up the dev server or run a production build. Instead, put changes in src/tailwind.css and restart the server/re-run the build.

I’d probably avoid committing tailwind.generated.css to source control since it’s a generated file.

Production Tailwind + CRA Build

1. Install Tailwind and Tools

We need Tailwind itself, and a couple tools to build it – namely, PostCSS and the autoprefixer plugin, along with npm-run-all to run the file watcher and PurgeCSS to minify our build output.

Install ‘em all at once.

npm install tailwindcss postcss-cli autoprefixer npm-run-all @fullhuman/postcss-purgecss

2. Create a PostCSS config file

PostCSS is a tool for building CSS. It supports using a variety of plugins to customize the process, and here we’ll be using Tailwind as a plugin along with autoprefixer (for browser compatibility) and PurgeCSS (for a smaller output file).

Create a file called postcss.config.js in the root of your CRA project, and paste this in:

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

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

  // Include any special characters you're using in this regular expression
  defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
})

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

This file is from the Tailwind docs, and I suggest reading that linked section for more on what the defaultExtractor regex does and some guidelines for writing your JSX/HTML.

With this in place, we can run the postcss command, which will in turn call Tailwind, and out will pop our generated Tailwind file. And in production build mode (when you run npm run build), PurgeCSS will strip out unused CSS classes.

3. Add a Step to the Build

To avoid ejecting from Create React App’s build system we’re going to modify package.json so that the npm start command will run both the PostCSS build and the CRA server.

The run-p command (run in parallel) that comes with the npm-run-all package is the secret sauce here.

Update the scripts section of package.json to look like this. (unless you’ve customized your scripts, you should be able to copy/paste this verbatim)

"scripts": {
  "build:tailwind": "postcss src/tailwind.css -o src/tailwind.generated.css",
  "watch:tailwind": "postcss -w src/tailwind.css -o src/tailwind.generated.css",

  "start": "run-p watch:tailwind start:react",
  "start:react": "react-scripts start",

  "prebuild": "npm run build:tailwind",
  "build": "react-scripts build",

  "test": "react-scripts test",
  "eject": "react-scripts eject"
},

We have build:tailwind and watch:tailwind scripts that are largely the same, except we’re passing the -w flag in watch mode.

(Note: The script name build:tailwind isn’t special. You could call it build:css or awesomeness or happydays if you wanted.)

Then, we renamed the existing start script to start:react so that we can add our own start script.

Our start script will run the watch:tailwind and start:react scripts in parallel. CRA and PostCSS co-existing harmoniously.

After you make these changes, start everything up with npm start and try changing src/tailwind.css. PostCSS will detect the change, write out a new src/tailwind.generated.css file, then CRA will detect that change and rebuild the React app, and the browser should refresh. Phew.

It’s a bit of a Rube Goldberg machine, but then again, so are most builds :)

NPM supports pre- and post- scripts

Fun fact: Scripts that start with the word “pre” are special to NPM (and Yarn). They automatically run before the named script.

Here, prebuild will run before the build script. When you run npm run build, NPM will run both automatically.

The prefix “post” will do the same kind of thing, but will run after the named script. (e.g. postbuild would run after build is finished)

4. Set up the Tailwind source CSS file

(this step is the same as in the Basic setup)

You probably noticed that our build step refers to a src/tailwind.css file. Create that now, and paste this in:

@tailwind base;
@tailwind components;
@tailwind utilities;

The Tailwind PostCSS plugin will replace these @tailwind directives with Tailwind’s generated CSS and write it out to src/tailwind.generated.css (that name is decided by the build:tailwind script we added to package.json).

5. Import the Generated CSS File

(this step is the same as in the Basic setup)

At the top of your index.js file, import the tailwind.generated.css file that’s being generated by PostCSS and Tailwind.

Then we can try out a few Tailwind classes to make sure it works.

import React from 'react';
import ReactDOM from 'react-dom';
import './tailwind.generated.css';

const App = () => (
  <div className="max-w-md mx-auto flex p-6 bg-gray-100 mt-10 rounded-lg shadow-xl">
    <div className="ml-6 pt-1">
      <h1 className="text-2xl text-blue-700 leading-tight">
        Tailwind and Create React App
      </h1>
      <p className="text-base text-gray-700 leading-normal">
        Building apps together
      </p>
    </div>
  </div>
);

ReactDOM.render(<App />, document.querySelector('#root'));

Start up the development server as usual with npm start.

That’s all there is to it!

Where to Make Changes

Don’t change tailwind.generated.css since your changes will be wiped out the next time you start up the dev server or run a production build. Instead, put changes in src/tailwind.css and restart the server/re-run the build.

I’d probably avoid committing tailwind.generated.css to source control since it’s a generated file.

Customize Tailwind

Tailwind has a bunch of good defaults. Nice set of colors. Good array of font sizes. Logical naming of classes. You definitely don’t need to configure anything out of the box. But if you want to customize it, you’ll need a tailwind.config.js file.

To create it, run npx tailwind init for a minimal config, or npm tailwind init --full for a complete config that you can tweak.

Tailwind will automatically pick up on that file, so we don’t need to change anything about our build.

Learn More About Tailwind

Hopefully this post got you up and running with Tailwind CSS. To learn more, check out their excellent documentation, and especially the screencasts that Adam put together. It was really helpful for me to see how he used Tailwind in practice, and the videos cover a lot of common things you’d want to build like card layouts, badges, navbars, and dropdown menus.

If you want to work on your general CSS chops (which will help you pick up Tailwind faster too), check out this CSS layout tutorial and the challenge I ran a few months back.