Using Tailwind CSS with Gatsby, React & Emotion Styled Components
Tags: tailwindcss, gatsby, emotion
Published: 2020-03-10 12:23:04

---
title: Using Tailwind CSS with Gatsby, React & Emotion Styled Components
published: true
date: 2019-10-20 14:08:00 UTC
tags: tailwindcss,gatsby,emotion
canonical_url: https://nystudio107.com/blog/using-tailwind-css-with-gatsby-react-emotion-styled-components
---

# Using Tailwind CSS with Gatsby, React & Emotion Styled Components

### Learn how to use the util­i­ty-first Tail­wind CSS with Emo­tion ​“CSS-in-JS” Styled Com­po­nents in a Gats­by JS + React project.

Andrew Welch / [nystudio107](https://nystudio107.com)

![Gatsby react emotion styled components](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/4124/gatsby-react-emotion-styled-components.jpg)

[Tail­wind CSS](https://tailwindcss.com/) is a util­i­ty-first CSS frame­work that allows for rapid­ly build­ing cus­tom designs, and it is some­thing I’ve adopt­ed as a stan­dard part of my workflow.

If you want to hear the why’s and how’s of Tail­wind CSS, check out the [Tail­wind CSS Util­i­ty-First CSS dev​Mode​.fm pod­cast episode](https://devmode.fm/episodes/tailwind-css-utility-first-css-with-adam-watham). For the pur­pos­es of this arti­cle, we’ll just assume you’re all on-board the Tail­wind Express like I am.

![Tailwind utility first css express](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/tailwind-utility-first-css-express.jpg)

Since I’m a fan of Tail­wind CSS, when I start­ed work­ing with [Gats­by](https://www.gatsbyjs.org/) & [React](https://reactjs.org/), I want­ed a way to bring Tail­wind with me. I end­ed up decid­ing to go with the [Emo­tion CSS-in-JS](https://emotion.sh/docs/introduction) approach, specif­i­cal­ly using [Styled Com­po­nents](https://emotion.sh/docs/styled).

Again, we’ll just assume you’re on-board with Emo­tion CSS-in-JS; if not, check out the [CSS in JS, an Emo­tion­al Top­ic dev​Mode​.fm pod­cast episode](https://devmode.fm/episodes/css-in-js-an-emotional-topic).

This arti­cle dis­cuss­es how to make all of these tech­nolo­gies play nice togeth­er, and explores some of the fun things the result­ing stack enables you to do.

If you want a head start on this set­up, check out Paulo Elias’s [gats­by-tail­wind-emo­tion-starter](https://github.com/pauloelias/gatsby-tailwind-emotion-starter) to get you going. Oth­er­wise, buck­le up and let’s dive right in!

## Why are we doing this?

If you haven’t worked with [CSS-in-JS](https://spin.atomicobject.com/2018/12/28/css-in-javascript-benefits/) or Styled Com­po­nents before, there are some nice advantages:

- You can use full-blown JavaScript
- CSS is scoped to just the com­po­nent, and does­n’t ​“bleed out”
- You auto­mat­i­cal­ly get just the CSS used on each page
- You auto­mat­i­cal­ly get Crit­i­cal CSS
- The end result is just CSS

You may or may not be con­vinced that CSS-in-JS is a good idea, but these are tan­gi­ble ben­e­fits that I’ve found, and thus my desire to use CSS-in-JS and Styled Components.

Adding Tail­wind CSS to the mix brings all of the won­der­ful ben­e­fits of a utilty-first CSS frame­work like Tail­wind CSS to our Styled Components.

So with that said, let’s get to it!

## A Hybrid Approach

The excel­lent [Gats­by doc­u­men­ta­tion](https://www.gatsbyjs.org/docs/) has two approach­es list­ed for using Tail­wind CSS with Gatsby:

- [Option #1: PostCSS](https://www.gatsbyjs.org/docs/tailwind-css/#option-1-postcss)
- [Option #2: CSS-in-JS](https://www.gatsbyjs.org/docs/tailwind-css/#option-2-css-in-js)

We’re actu­al­ly going to use a hybrid approach, using both the [tailwind.macro](https://github.com/bradlc/babel-plugin-tailwind-components) [Babel Macro](https://babeljs.io/blog/2017/09/11/zero-config-with-babel-macros) and [PostC­SS](https://postcss.org/).

We’re going to use the tailwind.macro to trans­late Tail­wind CSS class­es to Emo­tion Styled Com­po­nents for us, gen­er­at­ing just the CSS selec­tors we actu­al­ly use.

Then we’ll use PostC­SS for build­ing the [Tail­wind CSS base styles](https://tailwindcss.com/docs/adding-base-styles/) (and any base glob­al styles we want to use) that will be applied glob­al­ly to every page. This gives us things like the [Nor­mal­ize CSS reset](https://github.com/necolas/normalize.css/) as a base.

This is the rea­son for the hybrid approach: if we _just_ used the tailwind.macro, we would­n’t get any of the Tail­wind CSS base styles.

You could also use the [gats­by-theme-tail­wind­c­ss](https://github.com/talensjr/gatsby-theme-tailwindcss) Gats­by Theme as a way to scaf­fold things, but I think it makes sense to under­stand how all of the pieces fit togeth­er first.

So let’s get going by installing Tail­wind CSS:

```

# Using npm
npm install --save tailwindcss

# Using Yarn
yarn add tailwindcss

```

Next up, let’s get tailwind.macro set up!

## Set­ting up tailwind.macro

The tailwind.macro is a Babel Macro that allows you to use Tail­wind CSS with any CSS-in-JS library. We’ve cho­sen to use Emo­tion, so let’s get it all installed:

```

# Using npm
npm install --save @emotion/core @emotion/styled gatsby-plugin-emotion tailwind.macro@next

# Using Yarn
yarn add @emotion/core @emotion/styled gatsby-plugin-emotion tailwind.macro@next

```

Then we need to add the <kbd>gatsby-plugin-emotion</kbd> to our <kbd>gatsby-config.js</kbd> (in the project root):

```

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-emotion`,
      options: {
        // Accepts all options defined by `babel-plugin-emotion` plugin.
      },
    },
  ],
}

```

Then we need to cre­ate a <kbd>babel-plugin-macros-config.js</kbd> to tell it that we want to use Emo­tion, and where our <kbd>tailwind.config.js</kbd> file lives:

```

module.exports = {
    tailwind: {
        styled: '@emotion/styled',
        config: './tailwind.config.js',
        format: 'auto',
    }
};

```

Final­ly, there’s a [small issue](https://github.com/bradlc/babel-plugin-tailwind-components/issues/39) we need to work around, which appears to be due to Tail­wind CSS’s use of <kbd>reduce-css-calc</kbd> start­ing with <kbd>Tailwind ^1.1.0</kbd>, which appar­ent­ly depends on it being [run via Node](https://www.gitmemory.com/issue/TVke/react-native-tailwindcss/7/523364996).

We can work around this by adding the fol­low­ing to our <kbd>gatsby-node.js</kbd> file (in the project root):

```

exports.onCreateWebpackConfig = ({actions, getConfig}) => {
    // Hack due to Tailwind ^1.1.0 using `reduce-css-calc` which assumes node
    // https://github.com/bradlc/babel-plugin-tailwind-components/issues/39#issuecomment-526892633
    const config = getConfig();
    config.node = {
        fs: 'empty'
    };
};

```

## Using tailwind.macro

Now that we’ve got tailwind.macro installed, let’s have a look at how we can use it. It works very sim­i­lar to [Emo­tion Styled Com­po­nents](https://emotion.sh/docs/styled):

```

import React from 'react';
import tw from 'tailwind.macro';

const PageContainer = tw.div`
    bg-gray-200 text-xl w-1/2
`;

const Layout = ({children}) => (
    <PageContainer>
        {children}
    </PageContainer>
);

export default Layout;

```

This will cre­ate a Styled Com­po­nent that is com­posed of the styles from the Tail­wind CSS class­es list­ed in the tem­plate lit­er­al. There’s a [Github issue](https://github.com/bradlc/babel-plugin-tailwind-components/issues/4) that shows a good exam­ple of how this works.

In **devel­op­ment** :

```

import tw from 'tailwind.macro'
let styles = tw`w-1/2`

// ↓↓↓↓↓↓↓↓

import _tailwind from './path/to/your/tailwind.js'
let styles = {
  width: _tailwind.widths['1/2']
}

```

In **pro­duc­tion** (<kbd>NODE_ENV=production</kbd>):

```

import tw from 'tailwind.macro'
let styles = tw`w-1/2`

// ↓↓↓↓↓↓↓↓

let styles = {
  width: '50%'
}

```

You can see how it direct­ly uses the JavaScript Tail­wind CSS con­fig to extract styles. The only real down­side to this approach is that it will not work with [Tail­wind Plu­g­ins](https://tailwindcss.com/docs/plugins/).

Build­ing on the ini­tial exam­ple above, we can mix and match Emo­tion Styled Com­po­nents cus­tom CSS with Tail­wind class­es easily:

```

import React from 'react';
import styled from '@emotion/styled';
import tw from 'tailwind.macro';

import background from '../../static/fabric_plaid@2x.png';

const PageContainer = styled.div`
    ${tw`
        bg-gray-200 text-xl w-1/2
    `}
    background-image: url(${background});
    padding: 10px;
`;

const Layout = ({children}) => (
    <PageContainer>
        {children}
    </PageContainer>
);

export default Layout;

```

So it actu­al­ly _com­bines_ the CSS styles from the Tail­wind CSS class­es in the <kbd>${tw`</kbd> tem­plate lit­er­al with the cus­tom styled com­po­nent CSS below it. So you can do any of the fun pat­terns you do with [Emo­tion Styled Com­po­nents](https://emotion.sh/docs/styled), too!

In either case, only the CSS that is actu­al­ly used on a page will be extract­ed (no need for [PurgeC­SS](https://tailwindcss.com/docs/controlling-file-size/)), and the styles used by com­po­nents on a page will be inlined, appear­ing some­thing like this:

```

<style data-emotion="css">
    .css-14xcvvf-PageContainer {
        background-color:#edf2f7;
        font-size:1.25rem;
        width:50%;
        background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQBAMAAABykSv/AAAAG1BMVEXq6urr6+vp6eno6Ojn5+fs7Ozt7e3m5ubu7u7dMibkAAAf6ElEQVR4AdyX4W3jSgyEp4WvhWmBLaiFaWFbeC2k7AfNSoICHHC4vyISO8vlfOQAdGxL2PaMx);
        padding:10px;
    }
</style>

```

The hashed CSS class name ensures that the styles are scoped to just the com­po­nent they are applied to, and will not leak out and affect any­thing else.

Sweet!

## Set­ting up PostCSS

If we just left things as-is, using only the tailwind.macro, every­thing would still work, but we would­n’t get the Tail­wind CSS base styles to do things like apply a Nor­mal­ize CSS style reset, and oth­er glob­al styles.

Because these base styles are super use­ful, we’ll con­fig­ure PostC­SS to gen­er­ate them for us. So let’s install the PostC­SS pack­ages we’re going to use:

```

# Using npm
npm install --save gatsby-plugin-postcss postcss-import postcss-preset-env stylelint

# Using Yarn
yarn add gatsby-plugin-postcss postcss-import postcss-preset-env stylelint

```

Then we need to add the <kbd>gatsby-plugin-postcss</kbd> to our <kbd>gatsby-config.js</kbd> (in the project root):

```

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-emotion`,
      options: {
        // Accepts all options defined by `babel-plugin-emotion` plugin.
      },
    },
    {
      resolve: `gatsby-plugin-postcss`,
      options: {
        // Accepts all options defined by `gatsby-plugin-postcss` plugin.
      },
    },
  ],
}

```

We’ll also need to cre­ate a <kbd>postcss.config.js</kbd> file (in the project root) to tell it what PostC­SS plu­g­ins we want to use (includ­ing <kbd>tailwindcss</kbd>):

```

module.exports = {
    plugins: [
        require('postcss-import')({
            plugins: [
                require('stylelint')
            ]
        }),
        require('tailwindcss')('./tailwind.config.js'),
        require('postcss-preset-env')({
            autoprefixer: { grid: true },
            features: {
                'nesting-rules': true
            },
            browsers: [
                '> 1%',
                'last 2 versions',
                'Firefox ESR',
            ]
        })
    ]
};

```

The <kbd>postcss.config.js</kbd> file is used by PostC­SS to con­fig­ure the plu­g­ins and set­tings that PostC­SS will use. The impor­tant bit here is that we’re doing a <kbd>require('tailwindcss')</kbd> to include Tail­wind CSS.

The oth­er PostC­SS plu­g­ins we’re includ­ing here are just things that I find use­ful. You can read more about them in-depth in the [An Anno­tat­ed web­pack 4 Con­fig for Fron­tend Web Devel­op­ment](https://dev.to/gaijinity/an-annotated-webpack-4-config-for-frontend-web-development-5646-temp-slug-4335831) article.

Then we need to cre­ate a file for the Tail­wind CSS base styles, as well as any glob­al styles we might want to add in <kbd>src/utils/globals.css</kbd>:

```

@tailwind base;

// Add any global styles here

```

Final­ly, we need to load these styles in the <kbd>gatsby-browser.js</kbd> (in the project root):

```

import "./src/utils/globals.css"

```

That’s it! When we do a build, it’ll now gen­er­ate the Tail­wind CSS base styles, and any of our glob­al styles, and include them on the page. Here’s a trun­cat­ed ver­sion of what that looks like:

```

<style data-href="/styles.bf4a6a428ae909ee6f5e.css">
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */

html {
	line-height: 1.15;
	-webkit-text-size-adjust: 100%
}

body {
	margin: 0
}

main {
	display: block
}

/* Truncated here */
</style>

```

## Wrap­ping Up

That’s all she wrote! I’ve found that being able to inter­twine the famil­iar Tail­wind CSS styles that I’m used to with Emo­tion Styled Com­po­nents had cre­at­ed a real­ly com­pelling way to work with CSS.

In the process of actu­al­ly using CSS-in-JS and Styled Com­po­nents, I found that many of my uncer­tain feel­ings about it dis­ap­peared. It turned my frown upside down.

![Css in js emotions](https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/blog/_1200x675_crop_center-center_82_line/css-in-js-emotions.jpg)

Part of the rea­son is that all of this is just a real­ly sophis­ti­cat­ed way to gen­er­ate and scope CSS in a way that allows for an excel­lent devel­op­er experience.

And since we’re using Gats­by to ren­der every­thing out to sta­t­ic pages, it results in an excel­lent user expe­ri­ence too.

The fact that it ends up scop­ing the CSS to each com­po­nent, and auto­mat­i­cal­ly inlin­ing just the CSS that we use on each page is pret­ty fantastic.

It makes process­es like PurgeC­SS and Crit­i­cal CSS as described in the [Imple­ment­ing Crit­i­cal CSS on your web­site](https://dev.to/gaijinity/implementing-critical-css-on-your-website-37d5-temp-slug-6012917) arti­cle unnecessary.

Give it a whirl, and you might just [sec­ond that emo­tion](https://www.youtube.com/watch?v=mv9cWgkpIZ4).

## Further Reading

_If you want to be notified about new articles, follow [nystudio107](https://twitter.com/nystudio107) on Twitter._

<small>Copyright ©2020 nystudio107. Designed by nystudio107</small>