'Tailwind css classes not showing in Storybook build

I am trying to build my storybook with tailwind css. When running build-storybook the components are rendered with the tailwind classes. Unfortunately, when I build storybook and run the create build storybook-static with npx http-server storybook-static the classes are not loaded into the stories and the components are displayed not styled.

This is a repro repo of my project: https://gitlab.com/ens.evelyn.development/storybook-issue

This is my main.js :

    const path = require('path')

module.exports = {
  "stories": [
    "../src/components/**/**/*.stories.mdx",
    "../src/components/**/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    {
     name: '@storybook/addon-postcss',
     options: {
       postcssLoaderOptions: {
         implementation: require('postcss'),
       },
     },
   },        
   "@storybook/addon-actions",
    "storybook-tailwind-dark-mode"
  ]}

My Projectstructure looks like this:

.storybook 
src
  components 
     subdir
       Button
         index.tsx
         button.stories.js 
  styles
    index.css (<-- tailwindcss file)

Any hints or advice is very appreciated.



Solution 1:[1]

UPDATE: My original answer could be useful to others, so I'll leave it for reference. However, in this case, the problem was in tailwind.config.js.

Change

purge: {
    mode: 'all',
    content: [
      './src/components/**/**/*.{ts, tsx}'
    ],
  },

to

purge: ['./src/**/*.{js,jsx,ts,tsx}'],

ORIGINAL:

Just tested it out and storybook builds as expected for me. I think the key difference in our configurations is that I am not making changes to Storybook's webpack config in main.js. Rather, I am using @storybook/addon-postcss for postcss@^8 (required for tailwind@^2):

// main.js
module.exports = {
  ...
  addons: [
    ...
    {
      name: '@storybook/addon-postcss',
      options: {
        postcssLoaderOptions: {
          implementation: require('postcss'),
        },
      },
    },
  ],
};

I specify the necessary plugins in a postcss.config.js (in my project root):

// postcss.config.js
module.exports = {
    plugins: {
      tailwindcss: {},
      autoprefixer: {},
    },
  }

It's also worth noting that I import Tailwind directly in Storybook's preview.js instead via my own css file:

// preview.js
import 'tailwindcss/tailwind.css';
export const parameters = {...}

Hopefully, making those changes will get Tailwind working for you.

For comparison (see comments below), here are the contents of my build storybook-static directory:

contents of storybook-static directory

Solution 2:[2]

The above solutions will not work for Tailwind version > 3.0 because of JIT compiler.

Solution 1: Easy solution

in .storybook/preview.js file add this line to compile tailwind generated css files like this -

import '!style-loader!css-loader!postcss-loader!tailwindcss/tailwind.css';

Here tailwindcss/tailwind.css is the tailwind css file. Look, important is I've to add !postcss-loader! to compile tailwind generated css.

You can add also your custom scss file like this if any -

import '!style-loader!css-loader!sass-loader!../src/scss/style.scss';

Here ../src/scss/style.scss is custom scss file.

For most of the people this will work in Tailwind version > 3.0 without any issue.

Solution 2: Kinda Hack solution

Create a custom styled element in preview page

import tailwindCss from '!style-loader!css-loader!postcss-loader!sass-loader!tailwindcss/tailwind.css';
const storybookStyles = document.createElement('style');
storybookStyles.innerHTML = tailwindCss;
document.body.appendChild(storybookStyles);

Hope, this will help for new Tailwind users who are working in Tailwind greater than v3.0.

Solution 3:[3]

if you using storybook with TSdx and tailwind css you should be able to import a CSS into components

  1. To be able to import your CSS into components, you will need to tell TSDX how to include it with your code. For that, you will need to install rollup-plugin-postcss (as TSDX uses rollup).
  2. Create a CSS file in your src directory which we will use in any component in which we want to use Tailwind.

Alright, so now let's add rollup-plugin-postcss:

yarn add -D rollup-plugin-postcss

TSDX is fully customizable and you can add any rollup plugin, but be aware that it overrides the default behavior

Now you'll create a

tsdx.config.js

// tsdx.config.js

const postcss = require('rollup-plugin-postcss');

module.exports = {
  rollup(config, options) {
    config.plugins.push(
      postcss({
        config: {
          path: './postcss.config.js',
        },
        extensions: ['.css'],
        minimize: true,
        inject: {
          insertAt: 'top',
        },
      })
    );
    return config;
  },
};

This is giving a postCSS path, which tells it what files you want it to run on. The minimize key is to allow you to minimize the output. The most important key here is the "inject". you set it to "top" to tell postCSS where inside the of our page the CSS will be inserted. It's paramount for Tailwind as it needs to have the utmost priority of any other stylesheet.

Next, for part 2, you will create a tailwind.css (can be named anything else) file under the src directory and paste this in:

// src/tailwind.css
@tailwind base;
@tailwind components;
@tailwind utilities;

Add the CSS import statement to your component

// src/Thing.tsx

import React, { FC, HTMLAttributes, ReactChild } from 'react';

// ! Add the CSS import statement !
import './tailwind.css`;

// ...

// we'll add some Tailwind classes on our components to test

export const Thing: FC<Props> = ({ children }) => {
  return (
    <div className="flex items-center justify-center w-5/6 m-auto text-2xl text-center text-pink-700 uppercase bg-blue-300 shadow-xl rounded-3xl">
      {children || `the snozzberries taste like snozzberries`}
    </div>
  );
};

Solution 4:[4]

The following configuration will enable so Tailwind generate CSS as new tailwind classes are added to the markup in dev mode (hot reload).

In summary, I don't think @storybook/addon-postcss works with Tailwind JIT and Storybook hot reload, and the workaround is to use the postcss-loader webpack loader.

Install these deps:

@storybook/builder-webpack5 @storybook/manager-webpack5 postcss-loader webpack (must be version 5)

// .storybook/main.js
const path = require("path");

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    // {
    //   name: "@storybook/addon-postcss",
    //   options: {
    //     postcssLoaderOptions: {
    //       implementation: require("postcss"),
    //     },
    //   },
    // },
  ],
  framework: "@storybook/react",
  core: {
    builder: "webpack5",
  },
  webpackFinal: (config) => {
    config.module.rules.push({
      test: /\.css$/,
      use: [
        {
          loader: "postcss-loader",
          options: {
            postcssOptions: {
              plugins: [require("tailwindcss"), require("autoprefixer")],
            },
          },
        },
      ],
      include: path.resolve(__dirname, "../"),
    });
    return config;
  },
};
// .storybook/preview.js
import "../styles/globals.css";

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
};
// postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

Solution 5:[5]

I couldn't work this out and the above answered didn't work for me, so I eventually just set my build-storybook script to run tailwind itself after the build. package.json scripts looked like this in the end:

"build-storybook": "build-storybook -s public && $(npm bin -g)/tailwindcss -i storybook-static/static/css/main.*.chunk.css -o storybook-static/static/css/main.*.chunk.css -m",

Bit of a mess, but $(npm bin -g)/ here uses my globally installed (npm i -g tailwindcss) version of tailwindcss as the version installed to the project wasn't working in builds for me.

-i and -o specifies the input and output files, and -m minifies the output.

I can foresee this causing problems if more than one CSS file gets built (maybe using storybook-static/static/css/**/*.css would work instead?), but this might help someone just get something working.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Maniruzzaman Akash
Solution 3
Solution 4 Mikael Lirbank
Solution 5 Orchis