Building a Component Library

+15 Mana ✨

Create reusable components for your organization.

Library Structure

packages/ui/
├── src/
│   ├── components/
│   │   ├── Button/
│   │   │   ├── Button.tsx
│   │   │   ├── Button.test.tsx
│   │   │   ├── Button.stories.tsx
│   │   │   └── index.ts
│   │   ├── Input/
│   │   ├── Card/
│   │   └── Modal/
│   ├── hooks/
│   ├── utils/
│   └── index.ts
├── package.json
└── tsconfig.json

Component Pattern

tsx
// Button/Button.tsx
import { forwardRef } from 'react';
import { cn } from '../../utils/cn';
import type { ButtonProps } from './types';

export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant = 'primary', size = 'md', children, ...props }, ref) => {
    return (
      <button
        ref={ref}
        className={cn(
          'btn',
          `btn-${variant}`,
          `btn-${size}`,
          className
        )}
        {...props}
      >
        {children}
      </button>
    );
  }
);

Button.displayName = 'Button';

Type Exports

tsx
// Button/types.ts
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'ghost';
export type ButtonSize = 'sm' | 'md' | 'lg';

export type ButtonProps = {
  variant?: ButtonVariant;
  size?: ButtonSize;
  children: React.ReactNode;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

Public API

tsx
// src/index.ts

// Components
export { Button } from './components/Button';
export { Input } from './components/Input';
export { Card } from './components/Card';
export { Modal } from './components/Modal';

// Types
export type { ButtonProps, ButtonVariant } from './components/Button/types';
export type { InputProps } from './components/Input/types';

// Hooks
export { useModal } from './hooks/useModal';

// Utils
export { cn } from './utils/cn';

Package.json

json
{
  "name": "@company/ui",
  "version": "1.0.0",
  "main": "dist/index.js",
  "module": "dist/index.mjs",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./styles.css": "./dist/styles.css"
  },
  "files": ["dist"],
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "storybook": "storybook dev -p 6006"
  },
  "peerDependencies": {
    "react": ">=18.0.0",
    "react-dom": ">=18.0.0"
  }
}

Usage in Apps

tsx
// In an app
import { Button, Input, Card } from '@company/ui';
import '@company/ui/styles.css';

function LoginForm() {
  return (
    <Card>
      <Input label="Email" type="email" />
      <Input label="Password" type="password" />
      <Button variant="primary">Login</Button>
    </Card>
  );
}
✓ Completed