question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to configure tailwind css for use with storybook

See original GitHub issue

Bug or support request summary

I am trying to configure tailwind css with storybook, but since it requires some webpack configuration, it’s not as straightforward as other configs. At this point, I am not even sure if it’s possible currently.

Steps to reproduce

So far, I have tried to use custom webpack config (referring storybook and tailwind docs):

const path = require("path");
const tailwindcss = require("tailwindcss");

// Export a function. Accept the base config as the only param.
module.exports = (storybookBaseConfig, configType) => {
  // configType has a value of 'DEVELOPMENT' or 'PRODUCTION'
  // You can change the configuration based on that.
  // 'PRODUCTION' is used when building the static version of storybook.

  // Make whatever fine-grained changes you need
  storybookBaseConfig.module.rules.push({
    test: /\.scss$/,
    loaders: ["style-loader", "css-loader", "sass-loader", "postcss-loader"],
    include: path.resolve(__dirname, "../")
  });
  storybookBaseConfig.plugins = [
    tailwindcss("./tailwind.js"),
    require("autoprefixer")
  ];

  // Return the altered config
  return storybookBaseConfig;
};

But that gives an error:

info => Loading custom webpack config (full-control mode).
/Users/anishkumar/Documents/react/ez2/node_modules/tapable/lib/Tapable.js:375
		arguments[i].apply(this);
		             ^

TypeError: arguments[i].apply is not a function
    at Compiler.apply (/Users/anishkumar/Documents/react/ez2/node_modules/tapable/lib/Tapable.js:375:16)
    at webpack (/Users/anishkumar/Documents/react/ez2/node_modules/@storybook/core/node_modules/webpack/lib/webpack.js:33:19)
    at exports.default (/Users/anishkumar/Documents/react/ez2/node_modules/@storybook/core/dist/server/middleware.js:29:40)
    at buildDev (/Users/anishkumar/Documents/react/ez2/node_modules/@storybook/core/dist/server/build-dev.js:163:36)
    at Object.<anonymous> (/Users/anishkumar/Documents/react/ez2/node_modules/@storybook/react/dist/server/index.js:23:22)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Module.require (module.js:579:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/anishkumar/Documents/react/ez2/node_modules/@storybook/react/bin/index.js:3:1)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)

Please specify which version of Storybook and optionally any affected addons that you’re running

    "@storybook/react": "^3.4.10",
    "@storybook/addon-actions": "^3.4.10",
    "@storybook/addon-links": "^3.4.10",
    "@storybook/addons": "^3.4.10",

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:14 (2 by maintainers)

github_iconTop GitHub Comments

25reactions
Abramovickcommented, Mar 21, 2019

I did manage to get it working at the end. Just like @igor-dv mentioned, you shouldn’t put them in your webpack.config.js but rather in a postcss.config.js file. Once you set up PostCSS on Webpack, then set up Tailwind as a PostCSS plugin and it’ll get picked up. That’s what the Tailwind docs also say.

NOTE: I do over comment my code so you’ll have a lot to read as i post my code below.

// webpack.config.js

const path = require('path');

// Export a function. Accept the base config as the only param.
module.exports = ({ config, mode }) => {

  /* Support for React Native Web */
  config.resolve = {
    modules: ['node_modules'],
    extensions: ['.web.js', '.js', '.json', '.web.jsx', '.jsx', 'ts', 'tsx'],
    alias: {
      'react-native': 'react-native-web',
    },
  };

  /* PostCSS Support */
  config.module.rules.push({
    test: /\.css$/,
    loaders: [
      // Loader for webpack to process CSS with PostCSS
      {
        loader: 'postcss-loader',
        options: {
          /* 
            Enable Source Maps
           */
          sourceMap: true,
          /*
            Set postcss.config.js config path && ctx 
           */
          config: {
            path: './.storybook/',
          },
        },
      },
    ],

    include: path.resolve(__dirname, '../'),
  });

  /* TypeScript Support */
  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    use: [
      {
        // Typescript compiler
        loader: require.resolve('awesome-typescript-loader'),
      },
      {
        // Webpack loader to generate docgen information from Typescript React components.
        loader: require.resolve('react-docgen-typescript-loader'),
      },
    ],
  });

  config.resolve.extensions.push('.ts', '.tsx');

  // Return the altered config
  return config;
};

// postcss.config.js

var tailwindcss = require('tailwindcss');

module.exports = {
  plugins: [
    /*
      This plugin can consume local files, node modules or web_modules. To resolve path of an @import rule, it can look into root directory (by default process.cwd()), web_modules, node_modules or local modules. When importing a module, it will look for index.css or file referenced in package.json in the style or main fields. You can also provide manually multiples paths where to look at. 
     */
    require('postcss-import'),

    /*
      PostCSS plugin for mixins. 
      Note, that you must set this plugin before postcss-simple-vars and postcss-nested.

      Example
        @mixin icon twitter {
          background: url(twt.png);
        }
     */
    require('postcss-mixins'),

    /* 
      PostCSS plugin to reference any parent ancestor selector in nested CSS.

      When writing modular nested CSS, & current parent selector is often not enough.

      PostCSS Nested ancestors introduces ^& selector which let you reference any parent ancestor selector with an easy and customizable interface.
     */
    // require('postcss-nested-ancestors'),

    /* 
      PostCSS plugin to unwrap nested rules like how Sass does it.
     */
    require('postcss-nested'),

    /*
      PostCSS Preset Env lets you convert modern CSS into something most browsers can understand, determining the polyfills you need based on your targeted browsers or runtime environments.

      For more options read: https://github.com/csstools/postcss-preset-env#options
     */
    require('postcss-preset-env')({
      stage: 1,
    }),

    /*
      PostCSS plugin that tries to fix all of flexbug's issues 
     */
    require('postcss-flexbugs-fixes'),

    /* 
      Tailwind configuration
    */
    tailwindcss('./tailwind.config.js'),

    /*
      PostCSS plugin to parse CSS and add vendor prefixes to CSS rules using values from Can I Use.

      Write your CSS rules without vendor prefixes (in fact, forget about them entirely). Autoprefixer will use the data based on current browser popularity and property support to apply prefixes for you.
     */
    require('autoprefixer'),
  ],
};

4reactions
jozsefDevscommented, Jan 8, 2021

@ziodave 's solution works, but with the Create React App preset, only in dev mode, because it’s not filtering out the existing rules correctly. Here’s how I got it to work on the latest versions, using CRA:

const path = require('path')

module.exports = {
  stories: ['../src/**/*.stories.js'],
  addons: [
    '@storybook/preset-create-react-app',
    '@storybook/addon-knobs',
    '@storybook/addon-actions',
    '@storybook/addon-links',
  ],
  webpackFinal: (config) => {
    return {
      ...config,
      module: {
        ...config.module,
        rules: [
          // Filter out the default .css and .module.css rules and replace them with our own.
          ...(config.module.rules = config.module.rules.map((f) => {
            if (f.oneOf === undefined) {
              return f
            }

            return {
              oneOf: f.oneOf.map((r) => {
                if (r.test === undefined) {
                  return r
                }

                if (r.test.toString() === '/\\.css$/') {
                  return {
                    test: /\.css$/,
                    exclude: [/\.module\.css$/, /@storybook/],
                    include: path.resolve(__dirname, "../"),
                    use: [
                      'style-loader',
                      {
                        loader: 'css-loader',
                        options: { importLoaders: 1, sourceMap: false },
                      },
                      'postcss-loader',
                    ],
                  }
                }
                if (r.test.toString() === '/\\.module\\.css$/') {
                  return {
                    test: /\.module\.css$/,
                    exclude: [/@storybook/],
                    include: path.resolve(__dirname, "../"),
                    use: [
                      'style-loader',
                      {
                        loader: 'css-loader',
                        options: { importLoaders: 1, sourceMap: false, modules: true },
                      },
                      'postcss-loader',
                    ],
                  }
                }
                return r
              }),
            }
          })),
        ],
      },
    }
  },
}

This is super useful ⬆️ 🤯 💚

In addition to this, I have struggled a bit because I have CRA + Storybook + TS + Craco setup. I’m just makin a switch from SCSS to Tailwind.

So obviously I forgot to add a postcss.config.js inside the project root:

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

Also always remember that with Tailwind there is no import for the styles on component level (compared to simple CSS or CSS modules) so Webpack (used in Storybook) does not know where to grab the entry point for Tailwind.

❗️❗️❗️ To make this happen, be sure that you make a import 'index.css'; in .storybook/preview.js. This way as Webpack starts to load in, it can grab Tailwind’s entry point.

Sorry for the extension but I also needed these info to make this happen. Hopefully will help someone out there. 👋

Versions used:

    "react-scripts": "3.4.1",
    "@craco/craco": "^5.8.0",
    "@storybook/addon-actions": "6.0.21",
    "@storybook/addon-essentials": "6.0.21",
    "@storybook/addon-links": "6.0.21",
    "@storybook/node-logger": "6.0.21",
    "@storybook/preset-create-react-app": "3.1.4",
    "@storybook/react": "6.0.21",
    "@tailwindcss/aspect-ratio": "0.2.0",
    "@tailwindcss/postcss7-compat": "^2.0.2",
    "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.2",
    "tailwindcss-truncate-multiline": "1.0.3",
Read more comments on GitHub >

github_iconTop Results From Across the Web

Storybook-tailwind. How should I add tailwind to storybook
Storybook recommends using the @storybook/addon-postcss for customizing the postCSS config from now on (instead of relying on customizing ...
Read more >
How to set up Storybook with Next.js and Tailwind CSS
Complete configuration and setup for Storybook with Next.js and Tailwind CSS.
Read more >
Integrate Tailwind CSS with Storybook
How to setup Tailwind CSS and Storybook. Storybook.js is a fantastic tool for developing and showcasing UI components in isolation.
Read more >
Configure Tailwind for your Storybook Setup in an Nx ...
We want to have a library where to host our UI components s.t. they can be easily shared within our Nx workspace. In...
Read more >
Building a front end project with React, TailwindCSS and ...
The config files in the .storybook folder are available for us to customize down the line if we need to, and the src/stories...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found