Develop a Full-Fledged Component Library with React, just like Material UI

Tapajyoti Bose
5 min readMay 1, 2022

Always wondered how component libraries work in React? Want to create a library of your own, but the task seems too daunting? Fret no more! This article will teach you just that!

Let’s kick things off!

Initializing Project

Initialize a new project with

npm init

Add the dependencies using:

npm i react react-dom

Rename the dependencies in package.json to peerDependencies, which informs npm of the packages your project relies on.

Adding Storybook

Now comes the most tedious part of the setup.

Since you would need to test out the components you build, you could create a web app with all the components or use a tool like Storybook to easily test out your components.

Initialize a Storybook project with

npx sb init

This will automatically detect the project type, add the necessary packages & scripts.

Move the /src/stories folder to the root of your project (/stories) and update /.storybook/main.js with:

module.exports = {
// ...
stories: [
"../stories/**/*.stories.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx)",
],
};

You can now start up the storybook project with

npm run storybook

To add CSS Modules support to the project, install the following:

npm i -D @storybook/addon-postcss storybook-css-modules-preset

Update the /.storybook/main.js configuration with:

module.exports = {
// ...
addons: [
// ...
"@storybook/addon-postcss",
"storybook-css-modules-preset",
],
};

NOTE: Noticed that storybook’s dependencies are conflicting with React 18, if you get an error while starting up the storybook, try downgrading to React 17.

Create a Component

Now it’s finally time to create a component.

/* /src/Button/button.module.css */
.storybookButton {
font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: 700;
border: 0;
border-radius: 3em;
cursor: pointer;
display: inline-block;
line-height: 1;
}
.storybookButtonPrimary {
color: white;
background-color: #1ea7fd;
}
.storybookButtonSecondary {
color: #333;
background-color: transparent;
box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
}
.storybookButtonSmall {
font-size: 12px;
padding: 10px 16px;
}
.storybookButtonMedium {
font-size: 14px;
padding: 11px 20px;
}
.storybookButtonLarge {
font-size: 16px;
padding: 12px 24px;
}
// /src/Button/Button.js
import React from "react";
import classes from "./button.module.css";const Button = ({
primary,
backgroundColor,
size,
label,
...props
}) => {
const mode = primary
? classes.storybookButtonPrimary
: classes.storybookButtonSecondary;
return (
<button
type="button"
className={[
classes.storybookButton,
classes[`storybookButton${size}`],
mode,
].join(" ")}
style={backgroundColor && { backgroundColor }}
{...props}
>
{label}
</button>
);
};
export default Button;// /src/Button/index.js
export { default } from "./Button";

Since we are working on a component library, it is crucial to export the components in the main index.js file.

// /src/index.js
export { default as Button } from "./Button";

To test out the component, let’s add a story. Make sure you remove the default stories that were added by Storybook.

// /stories/Button.stories.js
import React from "react";
import { Button } from "../src";export default {
title: "Basics/Button",
component: Button,
argTypes: {
backgroundColor: { control: "color" },
},
};
const Template = (args) => <Button {...args} />;export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: "Button",
};
export const Secondary = Template.bind({});
Secondary.args = {
label: "Button",
};
export const Large = Template.bind({});
Large.args = {
size: "Large",
label: "Button",
};
export const Small = Template.bind({});
Small.args = {
size: "Small",
label: "Button",
};

Now you can run storybook and visit http://localhost:6006/?path=/story/basics-button--primary to checkout & modify the component on the fly.

Feel free to add as many components and stories as your library requires!

Building Project

What good is a project, that we cannot share with the world? Let’s build the project & distribute it on npm!

Install Rollup with

npm i -D rollup rollup-plugin-peer-deps-external rollup-plugin-postcss rollup-plugin-terser @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve

Setup Rollup Configuration

// /rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import { babel } from "@rollup/plugin-babel";
import external from "rollup-plugin-peer-deps-external";
import { terser } from "rollup-plugin-terser";
import postcss from "rollup-plugin-postcss";
export default {
input: "src/index.js",
output: [
{
file: "dist/index.js",
format: "cjs",
},
{
file: "dist/index.es.js",
format: "es",
exports: "named",
},
],
plugins: [
postcss({
plugins: [],
minimize: true,
}),
babel({
exclude: "node_modules/**",
presets: ["@babel/env", "@babel/preset-react"],
babelHelpers: "bundled",
}),
external(),
resolve(),
terser(),
],
external: ["react", "react-dom"],
};

Add the script to build the files:

// /package.json
{
// ...
"scripts": {
// ...
"build": "rollup -c"
}
}

Now you can build out the project with

npm run build

Now you can publish the project on npm! Just make sure it has a unique package name.

Wrapping Up

Material UI is a very mature library that has been around for years. Olivier definitely deserves a mention for creating such an outstanding library, used by even the humongous tech corporations!

If you want to create a library that truly competes with Material UI, you should be prepared to put in decades of grueling work first.

Best of luck!

Finding personal finance too intimidating? Checkout my Instagram to become a Dollar Ninja

Follow me for weekly new tidbits on the domain of tech

Need a Top Rated Front-End Development Freelancer to chop away your development woes? Contact me on Upwork

Want to see what I am working on? Check out my Personal Website and GitHub

Want to connect? Reach out to me on LinkedIn

I am a freelancer who will start off as a Digital Nomad in mid-2022. Want to catch the journey? Follow me on Instagram

--

--

Tapajyoti Bose

Top Rated Freelancer || Blogger || Cross-Platform App Developer || Web Developer || Open Source Contributor || FIRE Enthusiast