Component libraries are collections of reusable UI components that enable teams to build consistent user interfaces efficiently.
Benefits
- Consistency: Unified look and feel
- Speed: Build UIs faster
- Quality: Well-tested components
- Accessibility: Built-in a11y
- Documentation: Clear usage guidelines
Building Blocks
Button Component
typescript
// Button.tsx
import React from 'react';
import { variants, sizes } from './button-types';
interface ButtonProps {
children: React.ReactNode;
variant?: keyof typeof variants;
size?: keyof typeof sizes;
disabled?: boolean;
onClick?: () => void;
}
export const Button: React.FC<ButtonProps> = ({
children,
variant = 'primary',
size = 'medium',
disabled = false,
onClick
}) => {
const baseStyles = 'rounded font-medium transition-colors';
const variantStyles = variants[variant];
const sizeStyles = sizes[size];
const disabledStyles = disabled ? 'opacity-50 cursor-not-allowed' : '';
return (
<button
className={`${baseStyles} ${variantStyles} ${sizeStyles} ${disabledStyles}`}
disabled={disabled}
onClick={onClick}
>
{children}
</button>
);
};typescript
// button-types.ts
export const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
outline: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50',
danger: 'bg-red-600 text-white hover:bg-red-700'
};
export const sizes = {
small: 'px-3 py-1 text-sm',
medium: 'px-4 py-2 text-base',
large: 'px-6 py-3 text-lg'
};Documentation with Storybook
typescript
// stories/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline', 'danger']
},
size: {
control: 'select',
options: ['small', 'medium', 'large']
}
}
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Primary Button'
}
};
export const Secondary: Story = {
args: {
variant: 'secondary',
children: 'Secondary Button'
}
};
export const Sizes: Story = {
args: {
children: 'Button'
},
render: (args) => (
<div className="flex gap-4">
<Button {...args} size="small">Small</Button>
<Button {...args} size="medium">Medium</Button>
<Button {...args} size="large">Large</Button>
</div>
)
};Testing Components
typescript
// Button.test.tsx
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
describe('Button', () => {
it('renders children correctly', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('applies variant styles', () => {
const { container } = render(
<Button variant="primary">Primary</Button>
);
expect(container.firstChild).toHaveClass('bg-blue-600');
});
it('calls onClick when clicked', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click</Button>);
screen.getByText('Click').click();
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('is disabled when disabled prop is true', () => {
render(<Button disabled>Click</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
});Accessibility
typescript
// Accessible Icon Button
interface IconButtonProps {
icon: React.ReactNode;
label: string;
onClick?: () => void;
}
export const IconButton: React.FC<IconButtonProps> = ({
icon,
label,
onClick
}) => {
return (
<button
aria-label={label}
onClick={onClick}
className="p-2 hover:bg-gray-100 rounded"
>
{icon}
</button>
);
};Distribution
json
// package.json
{
"name": "@myorg/ui-library",
"version": "1.0.0",
"main": "dist/index.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "rollup -c",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}Best Practices
- 1Keep components focused
- 2Use TypeScript for type safety
- 3Document with Storybook
- 4Test thoroughly
- 5Make accessible
- 6Version semantically
- 7Get feedback early
Conclusion
Component libraries accelerate development and ensure consistency. Start with core components and grow systematically.