React + Tailwind CSS + Storybook

Learn how to setup React with Tailwind CSS and Storybook

React + Tailwind CSS + Storybook

After reading this from Tailwind, I was interested in the combination of React + Tailwindcss, so I will create a sample project and we will use Storybook so that we can we create and test components in an isolated view.

Create a sample app with create-react-app

cd /directory
npx create-react-app react-tailwind-sample
cd react-tailwind-sample
npm start

Install tailwindcss

Execute the following command referring to the page Install tailwind CRA app. And also install @tailwindcss/forms. Tailwind CSS supports PostCSS8 but CRA doesn't seem to so we will use PostCSS7.

  • npm i -D tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9

  • npm i @tailwindcss/forms

Install and configure CRACO

Configure and install CRACO by executing the command refferening to the tailwind css page.You need to change the Post CSS settings. npm i @craco/craco

After installing craco change scripts in package.json

Change react-scripts --> craco in scripts.

"scripts":{
    "start":"craco start",
    "build":"craco build",
    "test":"craco test",
    "eject":"craco eject"
}

In the root project directory create craco.config.js and write the following contents.

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

Config tailwind & postcss

Execute npx tailwindcss init -p in the root of the project . It will create a tailwind.config.js and postcss.config.js files

Modify tailwind.config.js as follows:-

module.exports = {
  purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [require("@tailwindcss/forms")],
};

and postcss.config.js remains the same:-

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

Change src/index.css

clear all the contents of src/index.css and add the following:-

@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind forms;

Change src/App.js

Make sure tailwindcss is available

change the src/App.js as follows:-

import "./App.css";
import "./index.css";
function App() {
  return (
    <div className="pt-4 pl-4 text-red-600 text-4xl font-extrabold">
      React + tailwindcss
    </div>
  );
}

export default App;

npm run start

You should get the text displayed in red color So now your frontend is working with Tailwind css. Next we will setup Storybook.

Install storybook

Run npx sb init

and then start the storybook

npm run start

You should get a dashboard of storybook displayed in your browser.

Now when you run our react application ie:- npm run start in another terminal you get an error related to multiple babel verisons. To resolve that we have to downgrade our babel. Execute the below command in terminal.

npm i -D babel-loader@8.1.0

after the version is down npm run start and we get the react logo screen

Modify .storybook/preview.js & .storybook/main.js

modify .storybook/preview.js as follows:

import "../src/index.css";

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

and modify .storybook/main.js as follows:

const path = require("path");

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app",
  ],
  webpackFinal: async (config) => {
    config.module.rules.push({
      test: /\,css&/,
      use: [
        {
          loader: "postcss-loader",
          options: {
            ident: "postcss",
            plugins: [require("tailwindcss"), require("autoprefixer")],
          },
        },
      ],
      include: path.resolve(__dirname, "../"),
    });
    return config;
  },
};

Delete /stories from /src.

Create a sample component and display in storybook

create src/components directory

create sample directory inside components and create a file ListItem.js and add the following:-

import React from "react";

const ListItem = ({ image, title, author }) => (
  <article className="p-2 flex space-x-4">
    <img className="flex-none w-16 h-16 rounded-lg" src={image} alt="" />
    <div>
      <div>
        <dt className="sr-only">Title</dt>
        <dd className="text-2xl font-bold">{title}</dd>
      </div>
      <div className="mt-0.5">
        <dt className="sr-only">Author</dt>
        <dd className="text-sm font-semibold text-indigo-500">By {author}</dd>
      </div>
    </div>
  </article>
);

export default ListItem;

and create another file ListItem.stories.js and add the following content:-

import React from "react";

import ListItem from "./ListItem";
import dog from "./dog.jpg";

export default {
  title: "sample/ListItem",
  component: ListItem,
};

const Template = (args) => <ListItem {...args} />;

export const Default = Template.bind({});

Default.args = {
  image: dog,
  title: "Pinku",
  author: "Criston",
};

Next lets describe the List component by creating a file called List.js

and add the following content:

import React from "react";

import ListItem from "./ListItem";

const List = ({ items }) => (
  <ul className="divide-y divide-gray-600">
    {items.map((item) => (
      <ListItem key={item.title} {...item} />
    ))}
  </ul>
);

export default List;

and then create ListItem.stories.js and add the following contents:

import React from "react";

import List from "./List";
import dog from "./dog.jpg";

export default {
  title: "sample/List",
  component: List,
};

const Template = (args) => <List {...args} />;

export const Default = Template.bind({});

Default.args = {
  items: [
    {
      image: dog,
      title: "Sample Book 1",
      author: "The author is a dog",
    },
    {
      image: dog,
      title: "Sample Book 1",
      author: "The author is a dog",
    },
    {
      image: dog,
      title: "Sample Book 1",
      author: "The author is a dog",
    },
  ],
};

Then open storybook you will see the component. Storybook will give us good documentation of a component and the team will be able to understand the components easily. We can use these components in our react app.


Referrenced sites/books