Design System Component
Category: Design Systems October 15, 2025
Create reusable, accessible design system components with documentation and variants.
Design SystemsComponentsUI/UXAccessibilityReusability
# Design System Component
Create a production-ready, reusable component for a design system with variants, accessibility, documentation, and tests.
## Component Requirements
### 1. API Design
- Props interface with TypeScript types
- Sensible defaults
- Flexible but not over-engineered
- Composable with other components
- Support for ref forwarding
### 2. Variants
- Size variations (small, medium, large)
- Style variations (primary, secondary, outline, ghost)
- State variations (default, hover, active, disabled, loading)
- Theme support (light, dark)
### 3. Accessibility
- Proper ARIA attributes
- Keyboard navigation support
- Focus management
- Screen reader friendly
- High contrast mode support
- WCAG 2.1 Level AA compliance
### 4. Styling
- CSS-in-JS or Tailwind classes
- Responsive design
- Animation and transitions
- Theme tokens integration
- CSS variables for customization
## Component Structure
```tsx
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
size?: 'sm' | 'md' | 'lg';
isLoading?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
}
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({
children,
variant = 'primary',
size = 'md',
isLoading = false,
disabled,
leftIcon,
rightIcon,
className,
...props
}, ref) => {
const baseStyles = "inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2";
const variants = {
primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
secondary: "bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500",
outline: "border border-gray-300 bg-transparent hover:bg-gray-50",
ghost: "bg-transparent hover:bg-gray-100"
};
const sizes = {
sm: "px-3 py-1.5 text-sm",
md: "px-4 py-2 text-base",
lg: "px-6 py-3 text-lg"
};
return (
<button
ref={ref}
className={cn(
baseStyles,
variants[variant],
sizes[size],
(disabled || isLoading) && "opacity-50 cursor-not-allowed",
className
)}
disabled={disabled || isLoading}
aria-busy={isLoading}
{...props}
>
{isLoading && <Spinner className="mr-2" />}
{leftIcon && <span className="mr-2">{leftIcon}</span>}
{children}
{rightIcon && <span className="ml-2">{rightIcon}</span>}
</button>
);
}
);
Button.displayName = 'Button';
Documentation
Storybook Stories
export default {
title: 'Components/Button',
component: Button,
} as Meta;
export const Primary = () => <Button variant="primary">Click me</Button>;
export const Secondary = () => <Button variant="secondary">Click me</Button>;
export const WithIcons = () => (
<Button leftIcon={<IconPlus />} rightIcon={<IconArrow />}>
Add Item
</Button>
);
export const Loading = () => <Button isLoading>Loading...</Button>;
Usage Examples
// Basic usage
<Button onClick={handleClick}>Submit</Button>
// With variant and size
<Button variant="primary" size="lg">Large Primary Button</Button>
// With icon
<Button leftIcon={<IconSave />}>Save Changes</Button>
// Loading state
<Button isLoading disabled>Saving...</Button>
Testing
describe('Button', () => {
it('renders children correctly', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('calls onClick when clicked', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
fireEvent.click(screen.getByText('Click me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('is disabled when isLoading is true', () => {
render(<Button isLoading>Click me</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
it('is accessible via keyboard', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
const button = screen.getByRole('button');
button.focus();
fireEvent.keyDown(button, { key: 'Enter' });
expect(handleClick).toHaveBeenCalled();
});
});
Component Checklist
- TypeScript types defined
- All variants implemented
- Accessible (ARIA, keyboard)
- Responsive design
- Theme support
- Documentation written
- Storybook stories created
- Tests written (>80% coverage)
- Peer reviewed
- Design approved