The Making of A React Component Library
Tags: javascript, react, webdev, beginners
Published: 2022-09-11 12:09:24

A component library is one of the coolest things a web developer can make, but if you don't know how to make one, let me guide you a bit.

Before we begin I would like to tell you, that I am not a pro at making component libraries, it's just from my experience developing a component library before.

## Prerequisites

Before you get started, these are the following you should know:

- Basics of React

- Typescript (Optional but preferred, you can use Javascript too)

## Why make a component library?

A react component library can be useful in many ways, you can use it in your projects as you scale and want uniformity or you can make your library open-source for everyone to use and contribute.

## Tools Required

- React - since, this is a tutorial about a react component library

- Typescript - this is optional but recommended

- Storybook - it's fine if you haven't heard of it, don't freak out. We will be using this to preview our components

## Getting Started

There are a lot of ways we can set up our library, if you want to make several packages in the same organization I would recommend using a monorepo but for the sake of this tutorial we will be setting up a very simple library from scratch.

So, first of all, go ahead and make a package.json file:

```bash
npm init
```

Once, you have initialized the project, we will start installing our dependencies. Unlike, in a normal project where you would just install the dependencies directly with `npm i [dep-name]`, here we will be using dev-dependencies and peer-dependencies.

Dev-dependencies are the dependencies that do not get packaged in the bundle and do not contribute to the size of our library, it is a dependency that you only require during development. 

Peer dependencies basically tell you that you need to have a certain package installed to use the library, for example, if I have a library named `avi-lib` and it has peer dependencies as `react` & `react-dom`, then if I want to use `avi-lib` in my project I need to have `react` & `react-dom` already installed as dependencies in the project.

Now go ahead and install `react` , `react-dom`, `tyepscript`, & `@types/react`, `@types/react-dom` as devDependencies.

```bash
yarn i -D react react-dom typescript @types/react @types/react-dom
```

Add `react` & `react-dom` as peer-dependencies with appropriate versions:

```json
{
    ...
    peerDependencies: {
        "react": ">=16.0.0",
        "react-dom": ">=16.0.0"
    }
    ...
}
```

Next, initialize a tsconfig file:

```bash
npx tsc --init
```

In the `tsconfig.json` file, go ahead and enable `jsx` with `"jsx": "react"` option.

## Making the Component

Once this is done make a directory `src` or whatever you wish to name it. This directory will contain all code.

Inside `src`, make another directory `components` and create a file `Button.tsx`. Now, open the file and write out a simple button:

```jsx
import React from 'react';

export interface ButtonProps {
  children: React.ReactNode;
  onClick: () => void;
}

export const Button = ({ children, onClick }: ButtonProps) => {
  return <button onClick={onClick}>{children}</button>;
};
```

Now inside the `src` directory, create a `index.ts` file, and write out the following:

```js
export { Button, ButtonProps } from "./components/Button"
```

## Storybook

Storybook is an amazing tool that is almost essential for component libraries, it helps you out with previewing your components adding documentation for them, and even lets you host the components for others to test. For the sake of this article, we will be primarily using it for testing our components.

To setup storybook in your library, run the following:

```bash
npx storybook --init
```

Storybook automatically detects that this is a react library and installs it accordingly. After it has done installing you will see a `.storybook` directory and a `src/stories` directory. You don't really have to do anything with the `.storybook` directory, you will use your components in the `src/stories` directory.

Inside the `src/stories` directory you will see a bunch of stuff, but don't worry about it, it is all just mock data. You can go ahead and empty it leaving only the `Button.stories.tsx`. Now you will see a lot of things in this file go ahead and empty it and type in the following:

```jsx
import React, { useState } from 'react';
import { storiesOf } from '@storybook/react';

import { Button } from '../';

const stories = storiesOf('Button', module);

stories.add('Button', () => {
  const [value, setValue] = useState('Hello');
  const setChange = () => {
    setValue(value === 'Hello' ? 'Bye' : 'Hello');
  };

  return <Button onClick={setChange}>{value}</Button>;
});
```

Now go ahead and check it out, run the following in your terminal:

```bash
npm run storybook
```

This will open a browser window on `localhost:6006`, and you can see our little button working, its `value` changes on being clicked.

That's about it, now go ahead and add your own magic to the button, make more components, and similarly, you can even create hooks.

## Documentation

It is a good idea to document things about your components in your library in a README file or on a docs website, it helps out anyone using your library. For the sake of this tutorial, we will not be writing documentation because it only contains a single button component.

## Bundling

Once you are done with making your components, let's bundle our library.

It's a good idea to bundle because it helps you produce a single file. Some people prefer dragging and dropping a single file in their projects. A single file can also be used for CDNs.

To bundle your component you will have to use a bundler. There are a lot of options out there but here we will be using [tsup](https://github.com/egoist/tsup) because tsup doesn't require a configuration for our use case.

To install tsup, do the following:

```bash
yarn add -D tsup
```

This installs tsup as a dev-dependency, now inside your `package.json` file add a script:

```json
{
    ...
    scripts: {
        ...
        "build": "tsup src/index.ts --dts"
    }
    ...
}
```

Now, go ahead and run `yarn build`, this will create a `index.js` file inside the `dist` directory. If you observe, we added a `--dts` in our build script, this will generate the type definitions for our project in `index.d.ts`. 

## Publishing

Now that all is done, it's time to show what you have built to the world (or not if it's for personal use). Before publishing, go to your `package.json` and you will find a few things, choose a name for your library and add an appropriate version (you can use [semantic versioning](https://semver.org/) if you don't know how to), a description of what it does, and a few keywords to make your library discoverable.

Now add a `.npmignore` file, this is very similar to `.gitignore`, this file will contain what you don't want to publish along with your library, for example, `node_modules`. Though this file is optional even if you don't include it, the `.gitignore` file will be used instead.

If you are not logged in to your npm account do `npm login` and you will have to enter your username and password. In the case, you don't have an npm account you can go to https://www.npmjs.com/ and register for one.

Once you have done that just simply run this command in the terminal:

```bash
npm publish
```

Once it finishes without any errors, Congrats! Your library has been published. Now you (and others too) can use your library in your projects.

## Tips

- Try to use typescript

- Add documentation in your README & if you want, a docs website

- I have not done it in the article but use git and make changes on a different branch than `main`

- Read more on Storybook, its templates, and documentation


## More Resources

- [Turborepo](https://turborepo.org/) - in case you wish to create a monorepo, you can also use [lerna](https://lerna.js.org/) instead of turborepo.

- [Storybook Documentation](https://storybook.js.org/)

Hope you enjoyed the read and learned something from it. In the case, you want to add something or find a mistake and wish to point it out, please feel free to do so in the comments.