loading...
Cover image for Integrating Gatsby, Tailwind, and Storybook

Integrating Gatsby, Tailwind, and Storybook

romansorin profile image Roman Sorin Updated on ・4 min read

A guide to the quick and easy setup of Storybook and Tailwind within Gatsby.

Gist: https://gist.github.com/romansorin/916cf914b90456f0ea584847d0db2db7

One of my current projects is dedicated to documenting and describing UX research that I’ll be conducting within the coming weeks/months. In building this project, I got the idea to use Tailwind, Gatsby, Firebase, and Storybook to get my hands dirty whilst still being able to build the app without too much effort.

In trying to do so, I had difficulty finding any sort of guide which covers how to use Tailwind and Gatsby with Storybook and found that traditional setup resulted in Tailwind styling to not work correctly or be loaded in. After coming to a working setup, I figured I'd release a guide to help others interested in integrating these.

Initial Setup

Start by creating a new Gatsby project:

    npm install -g gatsby-cli
    gatsby new tailwind-gatsby-storybook
    cd tailwind-gatsby-storybook
    gatsby develop

Dependencies

You'll need to install the associated Tailwind and Storybook dependencies, as per the Gatsby documentation. We'll start with installing TailwindCSS, the utility-first CSS framework that is, in my opinion, the best framework out there.

Tailwind setup:

    npm install tailwindcss --save-dev
    npx tailwind init


bash
This will install the framework and create a tailwind.config.js file, which can be used to theme and extend the framework.

Next, we'll setup PostCSS to work with Gatsby and Tailwind directive loading:

    npm install --save gatsby-plugin-postcss


bash
In your gatsby-config.js file, modify the plugins property to include this plugin:

    // gatsby-config.js

    plugins: [`gatsby-plugin-postcss`],

Create a postcss.config.js file in the root of your project:

    // postcss.config.js

    module.exports = () => ({
      plugins: [require("tailwindcss")],
    })

Now that the initial setup is completed, we can install Storybook for Gatsby. Later in the tutorial, we'll create/modify our app.css file (or whatever you intend on using) to utilize the Tailwind directives.

Storybook

Start by making sure you have the CLI installed. In the root of your project, run:

    npm install -g @storybook/cli
    sb init

This will create a .storybook folder in your project root which will contain storybook config files:

    .storybook/
        - addons.js
        - config.js

Edit the config.js file found in the .storybook directory:

    import { configure } from '@storybook/react'
    import { action } from '@storybook/addon-actions'

    // We will address this later.
    import '../src/components/layout.css'

    // automatically import all files ending in *.stories.js
    configure(require.context('../src', true, /\.stories\.js$/), module)

    // Gatsby's Link overrides:
    // Gatsby defines a global called ___loader to prevent its method calls from creating console errors you override it here
    global.___loader = {
      enqueue: () => {},
      hovering: () => {}
    }
    // Gatsby internal mocking to prevent unnecessary errors in storybook testing environment
    global.__PATH_PREFIX__ = ''
    // This is to utilized to override the window.___navigate method Gatsby defines and uses to report what path a Link would be taking us to if it wasn't inside a storybook
    window.___navigate = pathname => {
      action('NavigateTo:')(pathname)
    }

Note: It's important to pay attention to the directory specified in the configure(require.context(), module) statement. This will recursively scan the specified directory and import all *.stories.js files. For this tutorial (and as recommended by Gatsby docs) we've moved all stories into src.

Next, create a webpack.config.js within the .storybook directory:

    const path = require('path')

    module.exports = ({ config }) => {
      config.module.rules.push({
        test: /\.css$/,
        use: [
          // Loader for webpack to process CSS with PostCSS
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true,
              config: {
                path: './.storybook/'
              }
            }
          }
        ],

        include: path.resolve(__dirname, '../')
      })
      // Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
      config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]

      // use installed babel-loader which is v8.0-beta (which is meant to work with @babel/core@7)
      config.module.rules[0].use[0].loader = require.resolve('babel-loader')

      // use @babel/preset-react for JSX and env (instead of staged presets)
      config.module.rules[0].use[0].options.presets = [
        require.resolve('@babel/preset-react'),
        require.resolve('@babel/preset-env')
      ]

      config.module.rules[0].use[0].options.plugins = [
        // use @babel/plugin-proposal-class-properties for class arrow functions
        require.resolve('@babel/plugin-proposal-class-properties'),
        // use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
        require.resolve('babel-plugin-remove-graphql-queries')
      ]

      // Prefer Gatsby ES6 entrypoint (module) over commonjs (main) entrypoint
      config.resolve.mainFields = ['browser', 'module', 'main']

      return config
    }

This is almost identical to the configuration provided at the Gatsby docs, but includes the PostCSS loader. If you're using Typescript in your project, refer to the Gatsby docs on proper setup.

At this point, your project structure will look something like this (only including relevant files):

    tailwind-gatsby-storybook/
    ├── .storybook/
        ├── addons.js
        ├── config.js
        ├── taildwind.config.js
    ├── src/
        ├── components/
            ├── stories/
                ├── Examples.stories.js
    ├── tailwind.config.js
    ├── postcss.config.js
    ├── gatsby-config.js

Note that we haven't created the necessary CSS files for directives yet, so that is not included here.

Final Setup

We'll now need to create our app's main CSS file to hold our directives in, and make sure it's referenced correctly in our config files.

Start by creating a layout.css file (or similarly named):

    touch ./src/components/layout.css

Modify the file:

    @tailwind base;

    @tailwind components;

    @tailwind utilities;

Check that the reference to this file in .storybook/config.js is set correctly:

    import '../src/components/layout.css'

This should point directly to the file.

And that's it! You can now build Storybook stories and use Tailwind + React inside of it.

Conclusion

Given the popularity and recent growth of things like Gatsby, Tailwind, and Storybook, I figured it would pay off to be able to integrate all of these properly. Having found both Tailwind and Gatsby to be super helpful, rapid tools for development and MVP in isolated environments, this integration with Storybook for UI testing/style guide can increase the perceived productivity tenfold.

You can find me on:

Posted on by:

romansorin profile

Roman Sorin

@romansorin

Full-stack developer primarily using Laravel, React, and Vue.

Discussion

markdown guide