Add Tailwind to a Gatsby project

14 May 2020

Tailwind CSS is a highly customizable, low-level CSS framework that gives you all of the building blocks you need to build bespoke designs without any annoying opinionated styles you have to fight to override.

Tailwind CSS has completely changed the way I develop web apps thanks to the utility first workflow. And the recent release of v1.4 made it even easier to get a very small production build by including PurgeCSS as a built-in process. If you've been on the fence about trying out this great framework now is the time to jump in.

Create the Gatsby app

We'll keep things simple and generate a Gatsby app using npx and the very barebone Hello World starter.

npx gatsby new gatsby-tailwind https://github.com/gatsbyjs/gatsby-starter-hello-world

Once that has installed be sure to change into the newly created gatsby-tailwind project directory.

Add Tailwind to the project

Install the required dependencies

Install the development dependencies from our project root.

npm install --save-dev tailwindcss autoprefixer

Tailwind doesn't include any vendor prefixes out of the box so we'll be relying on autoprefixer to generate those for our final build.

Create the Tailwind CSS

I usually prefer to create a dedicated styles directory under src/styles when working on a project with Tailwind.

Create the directory and our global CSS file now.

mkdir -p src/styles && touch src/styles/main.css

To add Tailwind to our Gatsby project, we need simply add the @tailwind directives inside src/styles/main.css. These directives will be replaced with the actual Tailwind CSS during the build.

@tailwind base;
/* Your own custom base styles */

@tailwind components;
/* Your own custom component styles */

@tailwind utilities;
/* Your own custom utilities */

This src/styles/main.css file will be our global CSS file for the entire app. It will contain all of our project's pre-generated CSS including any of our extra custom CSS. The beauty and strength of using Tailwind is that you won't be required to write much extra CSS though.

Generate the Tailwind configuration

./node_modules/.bin/tailwindcss init

An empty tailwind.config.js file is generated within the project root. This config file allows us to dramatically customise Tailwind and is one of the single biggest strengths of this excellent framework. To read more on how you can configure Tailwind check the official configuration documentation.

Import the CSS into our App

There are two options to import a global CSS file into our app:

  • Import it via a gatsby-browser.js configuration file.
  • Import it into a Layout higher order component.

To keep things simple we'll cover the gatsby-browser.js option in this article.

Create a gatsby-browser.js file in your project root.

touch gatsby-browser.js

Now open the gatsby-browser.js file you just created and simply import the pre-generated Tailwind CSS file to finish the setup.

import './src/styles/main.css';

Personally, I usually use a Layout Component as my preferred approach. If you're curious you can learn more about using a layout component in Gatsby. If you go the layout component route you then need to import src/styles/main.css into that file only and not the gatsby-browser.js configuration file.

Create the PostCSS configuration

One of the strengths of Gatsby is the rich plugin ecosystem that already exists to easily add any extra functionality we may require.

Install the PostCSS plugin for Gatsby.

npm install --save gatsby-plugin-postcss

Activate the plugin by adding 'gatsby-plugin-postcss' to the plugins array within the gatsby-config.js file in the project root.

module.exports = {
  plugins: ['gatsby-plugin-postcss'],
};

Next we need to create a postcss.config.js file in the root of your project.

touch postcss.config.js

And populate the file with our PostCSS configuration.

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

We'll be using PostCSS to build our CSS by first running our application's CSS through the Tailwind CLI. This step not only replaces all of the @tailwind directives with the base, components and utilities from Tailwind but also applies your own tailwind.config.js customisations during the build. I cannot emphasise enough just how powerful the customisation options are and the massive amount of time it can save you. So please do spend time reading up on how to customise Tailwind to truly make it your own.

Since Tailwind does not include vendor prefixes, the output of the Tailwind build step is then sent into autoprefixer which will automatically add any vendor prefixes required by our browserlist (or a default set if none is explicitly set in our package.json).

Optimise the production build

Test the build

At this stage we have only imported the framework but aren't actually using any of the Tailwind classes in our application.

Replace src/pages/index.js with the below code. Notice that we have now made use of a few of Tailwind's classes such as text-5xl and mx-auto.

import React from 'react';

function Index() {
  return (
    <div className="container mx-auto">
      <main className="text-center">
        <h1 className="text-5xl font-semibold my-5">
          Welcome to{' '}
          <a href="https://gatsbyjs.org" className="text-purple-600">
            Gatsby.js!
          </a>
        </h1>

        <p className="description">
          Get started by editing{' '}
          <code className="font-mono bg-gray-200 p-1 rounded">
            src/pages/index.js
          </code>
        </p>
      </main>
    </div>
  );
}

export default Index;

Lets run a quick production build.

npm run build

Once that has completed open the generated CSS found in the newly created public directory. This generated CSS file is absolutely massive and contains the entirety of the framework including tons of styles we haven't used at all! Tailwind will even warn us that our styles are not being purged during the build process.

Unoptimised Tailwind build

This is expected behaviour at this point given our settings. It's important to note that the development build of Tailwind is large by design ensuring all of the framework's classes are available to you while you build the site. You will only ever use a small percentage of these and Tailwind provides a convenient way to trim that down for your production builds.

Update the Tailwind configuration.

The setup for running PurgeCSS used to be a little more involved requiring us to install extra dependencies and adding a regex pattern to our PostCSS configuration. Thankfully this is now a built-in feature as of version 1.4 and requires nothing more than defining the file patterns that may contain our Tailwind classes.

Replace the contents of the tailwind.config.js file in your project's root to include an array of file patterns.

module.exports = {
  purge: ['./src/**/*.js'],
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
};

Now that we have the purge settings in place, Tailwind will look through those files and treeshake any unused styles from the final production build. We have only set Tailwind to look through JavaScript files inside of our src directory. Be sure to tailor this to your own requirements such as adding posts/**/*.mdx if you start using MDX for your local posts.

If you're curious, read more about how Tailwind controls the file size for production builds.

Test the optimised Production Build

Now that we have set our purge options, we are ready to run the optimised production build. It will now automatically remove all unused classes from the final build.

npm run build

Once that completes open the newly generated production CSS file. You should find it has shrunk down considerably and now only contains the styles we have thus far used in our project. Perfect!

Conclusion

Tailwind CSS truly has had a huge impact on improving my workflow when developing web apps and I cannot imagine starting a new project without first reaching for this framework. Gatsby's rich plugin ecosystem makes it super easy to include Tailwind in your next build so be sure to give it a try.

Share this article
Was this post helpful?
Buy me a coffeeBuy me a coffee
About
I am a London based web developer currently focused on JavaScript, Node and React. Get in touch if you wish to compare eslint configs or debate the deadliest enemy in videogame history (spoiler alert: it was the first goomba).
© 39digits 2020