Beginner Guide to React Storybook
Tags: javascript, react, storybook, webdev
Published: 2024-06-10 08:24:17

**## Storybook**

Storybook is a powerful open source tool that allows developers to develop UI components isolated from business logic and context of app.

Storybook provides an interactive playground to develop and browse your component. 

Change on one component won't affect the others.

Without embedding it to your app, it can serve as a workshop environment to see how components look and behave in various state.


**## Getting Started with Storybook**

Developing a reusable UI is important aspect for developing modern web app, which will enable us to efficient and streamlined development process.

In this article, we will explore how to create a robust UI components using React, Storybook, Typescript and tailwind.

**## Setting up the environment**

1. Install Node.js and npm (Node Package Manager) on your pc. You can 
   download it from (https://nodejs.org/en)

2. Create a New Folder with name learn_storybook for your ui library and 
   navigate to its terminal . Run following command:

   

```
npm create vite@latest my-storybook-project -- --template react-ts
```
 
This command will create a new react app with typescript template . Your project name here is my-storybook-project. You can change it if you want.

```
cd my-storybook-project
```

## Installing dependencies

```
npx storybook@latest init
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8g179uwd8o7f24vpgn1.png)

This will setup Storybook.

```
npm install -D tailwindcss postcss autoprefixer
```
This will install Tailwind css , postcss and autoprefixer.


**## Configuring Tailwind css**

1. Create tailwind.config.ts

```
export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: { 
    },
  },
  plugins: [],
};

```

2. create a postcss.config.js file in the project root

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

3. Finally, import Tailwind css in your src/index.css

```
@tailwind base;
@tailwind components;
@tailwind utilities;
```

4. In Storybook configuration folder i.e. .storybook, open preview.ts and add 

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

Now , our environment is setup , we will now create a components  inside src folder .


Lets create a folder called components (you can delete the stories folder, inside src which was created by default while we setup the storybook ,if you want).

You can create a new folder inside the components directory for each ui component which you want to work with.

Here , let's create a folder called breadcrumb inside components folder. We will now create a breadcrumb component and it's stories.

Inside breadcrumb folder , create Breadcrumb.tsx file and __docs__ folder. Inside __docs__ folder , create Breadcrumb.stories.tsx file as in the figure :

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b9xiu71zagj38yg9pwn1.png)


Now add this code inside **BreadCrumb.tsx**

```
import React, { ReactNode } from "react";

/* eslint-disable @typescript-eslint/no-explicit-any */
export function slugify(text: any) {
  return text
    .toString()
    .toLowerCase()
    .replace(/\s+/g, "-") // Replace spaces with -
    .replace(/[^\w-]+/g, "") // Remove all non-word characters
    .replace(/--+/g, "-") // Replace multiple - with single -
    .replace(/^-+/, "") // Trim - from start of text
    .replace(/-+$/, ""); // Trim - from end of text
}

interface BreadcrumbsProps {
  title: string | ReactNode;
  path?: { id: number; link: string; label: string }[];
  children?: ReactNode;
  previcon?: React.JSX.Element;
  onClick?: () => void;
}
const Breadcrumbs: React.FC<BreadcrumbsProps> = ({
  title,
  path,
  children,
  previcon,
  onClick,
}) => {
  return (
    <div
      className={`breadcrumb  bg-danger-0 px-6 py-4 flex  items-center gap-5 breadcrumb-${
        title ? slugify(title) : "default"
      }`}
    >
      {previcon && (
        <div
          className="icon w-[36px] h-[36px] inline-flex items-center justify-center border border-neutral-200 rounded cursor-pointer"
          onClick={onClick}
        >
          {previcon}
        </div>
      )}
      <div
        className={`inline-flex flex-wrap items-center justify-between  ${
          previcon ? "w-[calc(100%_-_50px)]" : "w-full"
        }`}
      >
        <div className="title-wrap">
          {title && (
            <h1 className="text-2xl text-neutral-500 font-semibold">{title}</h1>
          )}

          {path && (
            <ul className="breadcrumb list-none flex items-center gap-1">
              {path
                .filter((path) => path?.label !== "")
                .map((segment) => (
                  <>
                    {segment.label === "" ? undefined : (
                      <li
                        key={segment?.id}
                        className="breadcrumb-item font-normal text-sm inline-flex after:content-['/'] after:block last:after:content-none after:ml-1 after:text-gray-500"
                      >
                        {(() => {
                          switch (true) {
                            case segment?.id !== path.length - 1:
                              return (
                                <a
                                  href={segment?.link ?? "/"}
                                  className="text-gray-500"
                                >
                                  {segment?.label}
                                </a>
                              );
                            default:
                              return (
                                <span className="text-gray-800">
                                  {segment?.label}
                                </span>
                              );
                          }
                        })()}
                      </li>
                    )}
                  </>
                ))}
            </ul>
          )}
        </div>
        {children && (
          <div className="other-accessories ml-auto flex flex-wrap gap-4">
            {children}
          </div>
        )}
      </div>
    </div>
  );
};

export default Breadcrumbs;

```
This component accepts title , breadcrumb paths , prevIcon, children and onClick event to trigger prevIcon Icon.



Inside **Breacrumb.stories.tsx**, add :

```
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";
import { fn } from "@storybook/test";
import Breadcrumbs from "../Breadcrumb";

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction

const path = [
  {
    id: 0,
    link: "/",
    label: "Home",
  },
  {
    id: 1,
    link: "/news",
    label: "News",
  },
  {
    id: 2,
    link: "/nepal-win-the-race",
    label: "Nepal win the race",
  },
];
const PrevPageSvg = () => (
  <svg
    width="20"
    height="20"
    className="cursor-pointer"
    viewBox="0 0 20 20"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
  >
    <path
      d="M17.5005 10.0003C17.5005 10.1661 17.4346 10.3251 17.3174 10.4423C17.2002 10.5595 17.0413 10.6253 16.8755 10.6253H4.63409L9.19268 15.1832C9.25075 15.2412 9.29681 15.3102 9.32824 15.386C9.35967 15.4619 9.37584 15.5432 9.37584 15.6253C9.37584 15.7075 9.35967 15.7888 9.32824 15.8647C9.29681 15.9405 9.25075 16.0095 9.19268 16.0675C9.13461 16.1256 9.06567 16.1717 8.9898 16.2031C8.91393 16.2345 8.83261 16.2507 8.75049 16.2507C8.66837 16.2507 8.58705 16.2345 8.51118 16.2031C8.43531 16.1717 8.36637 16.1256 8.3083 16.0675L2.6833 10.4425C2.62519 10.3845 2.57909 10.3156 2.54764 10.2397C2.51619 10.1638 2.5 10.0825 2.5 10.0003C2.5 9.91821 2.51619 9.83688 2.54764 9.76101C2.57909 9.68514 2.62519 9.61621 2.6833 9.55816L8.3083 3.93316C8.42558 3.81588 8.58464 3.75 8.75049 3.75C8.91634 3.75 9.0754 3.81588 9.19268 3.93316C9.30996 4.05044 9.37584 4.2095 9.37584 4.37535C9.37584 4.5412 9.30996 4.70026 9.19268 4.81753L4.63409 9.37535H16.8755C17.0413 9.37535 17.2002 9.4412 17.3174 9.55841C17.4346 9.67562 17.5005 9.83459 17.5005 10.0003Z"
      fill="#121212"
    />
  </svg>
);
const meta: Meta = {
  title: "components/BreadCrumb",
  component: Breadcrumbs,
  tags: ["autodocs"],
} satisfies Meta<typeof Breadcrumbs>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Primary: Story = {
  args: {
    title: "Breadcrumb Page",
    path: path,
    children: <div>add anything here</div>,
    previcon: <PrevPageSvg />,
    onClick: fn(),
  },
};

```
This file defines stories of Breacrumb from where we can implement the path of the pages with title along with prev button and the children , where we can add anything we need more .


**## Running Storybook**
 
To run storybook,  add following code :

```
npm run storybook
```

This will start storybook development server. Now, You can see the Breadcrumb component in the Storybook interface.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gbc848pr6d44ents48ro.png)


**## Conclusion**

We have now successfully created a react ui using storybook, typescript, tailwind using vite.

Now we can use this stories and component on your projects, share with others.

From this we came to know that , storybook provides a solid foundation for building scalable and maintainable ui component in react.