From Scratch to Publishing: Constructing a React Component Library on NPM


A component library is a curated collection of reusable UI elementsβsuch as buttons, inputs, and modalsβthat share a consistent design language and behavior.
Why it matters in 2025:
π Faster Development β Stop rebuilding the same components across projects.
π― Consistency β Maintain a unified design system across apps.
π€ Collaboration β Teams can share and maintain components in one place.
β»οΈ Reusability β Write once, use everywhere (web, hybrid apps, even across brands).
Whether youβre a solo dev or part of a large engineering team, a well-structured React component library saves time, reduces bugs, and ensures design consistency.
Project Setup
For 2025, the recommended setup combines Vite (for speed) or create-react-library
with TypeScript (for type safety).
Step 1: Create a library project
npm create vite@latest my-component-library --template react-ts
cd my-component-library
Step 2: Folder Structure
my-component-library/
βββ src/
β βββ components/
β βββ index.ts
β βββ styles/
βββ stories/
βββ tests/
βββ dist/
βββ package.json
βββ tsconfig.json
Core Components
Start with simple but essential components:
Button.tsx
import React from 'react';
type ButtonProps = {
label: string;
onClick?: () => void;
};
export const Button = ({ label, onClick }: ButtonProps) => {
return (
<button onClick={onClick} className="btn-primary">
{label}
</button>
);
};
β Design Pattern Used: Component Composition Pattern β allows combining components and props for flexibility.
Also create:
Input.tsx β accessible form input with labels.
Modal.tsx β controlled modal with
isOpen
andonClose
props.
Styling Options
CSS Modules β Scoped CSS for predictable styles.
Styled Components β Dynamic styling with props.
Tailwind-friendly β Utility-first styling for rapid iteration.
2025 Trend: Many libraries now use Tailwind + Variants for consistency and customization.
Documentation with Storybook
Storybook lets you visually test and document components.
Install:
npx storybook@latest init
Example story:
import { Button } from '../src/components/Button';
export default { title: 'Button', component: Button };
export const Primary = () => <Button label="Click Me" />;
Testing Your Components
Use Jest + React Testing Library for functional tests and Axe/Lighthouse for accessibility checks.
Example test:
import { render, screen } from '@testing-library/react';
import { Button } from '../components/Button';
test('renders button with label', () => {
render(<Button label="Test" />);
expect(screen.getByText(/Test/i)).toBeInTheDocument();
});
Publishing to NPM
Step 1: Update package.json
{
"name": "my-component-library",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"peerDependencies": { "react": ">=18" }
}
Step 2: Build
npm run build
Step 3: Publish
npm login
npm publish --access public
Usage Example
import { Button } from 'my-component-library';
export default function App() {
return <Button label="Hello World" onClick={() => alert('Clicked!')} />;
}
By building and publishing your own React component library, youβre not just writing reusable codeβyouβre creating a foundation for faster, cleaner, and more scalable development in every future project.
Subscribe to my newsletter
Read articles from Prashant Dasnur directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Prashant Dasnur
Prashant Dasnur
Iβm an MCA graduate with a passion for building modern web applications.Currently exploring Laravel and React, and sharing my learning journey through blogs and projects.I enjoy solving real-world problems with clean code and creative thinking.Always learning, always building. π»π