Component Design System
Build reusable UI components with Tailwind CSS and class-variance-authority
I use shadcn/ui as the foundation for my component library. Unlike traditional component libraries, shadcn/ui gives you the source code — meaning full control over styling and behavior. Components are built with Radix UI primitives (for accessibility), styled with Tailwind CSS, and use class-variance-authority (CVA) for variant management. This pattern lets me create consistent components with variants (size, color, state) while keeping the API simple and type-safe.
I use shadcn/ui + Radix UI + CVA for accessible, customizable components. You could achieve similar results with Material UI, Chakra UI, Ant Design, or building from scratch with Headless UI. The variant pattern shown here (using CVA) can also be implemented with plain Tailwind classes, CSS Modules, or styled-components.
How it works
components/
├── ui/
│ ├── button.tsx # Button component with variants
│ ├── input.tsx # Input component
│ ├── card.tsx # Card components (Card, CardHeader, etc.)
│ ├── dialog.tsx # Dialog/Modal component
│ └── separator.tsx # Separator component
└── common/
├── Container.tsx # Layout container
├── Logo.tsx # Logo component
└── ThemeToggle.tsx # Theme switcher
lib/
└── cn.ts # Utility for merging class names
styles/
└── globals.css # Global styles & CSS variablesDesign Tokens
CSS variables for consistent colors and theming.
Composable
Build complex UIs from small reusable components.
CVA Variants
Type-safe component variants with class-variance-authority.
Radix Primitives
Accessible, unstyled components from Radix UI.
Key Features
- •Variant-based component API
- •Composable and reusable patterns
- •Accessible components (Radix UI)
- •Type-safe props with TypeScript
- •Consistent design tokens
Live Example
Buttons
<Button>Default</Button> <Button variant="secondary">Secondary</Button> <Button variant="outline">Outline</Button> <Button variant="ghost">Ghost</Button> <Button variant="destructive">Destructive</Button> <Button size="sm">Small</Button> <Button size="lg">Large</Button>
Input Fields
<Input placeholder="Default input" /> <Input placeholder="Disabled input" disabled /> <div className="flex gap-2"> <Input placeholder="Search..." className="flex-1" /> <Button>Search</Button> </div>
Cards
Simple Card
A basic card component with header and content.
Highlighted Card
A card with primary border highlight.
<Card>
<CardHeader>
<CardTitle>Simple Card</CardTitle>
</CardHeader>
<CardContent>
<p>A basic card component with header and content.</p>
</CardContent>
</Card>
<Card className="border-primary">
<CardHeader>
<CardTitle className="text-primary">Highlighted Card</CardTitle>
</CardHeader>
<CardContent>
<p>A card with primary border highlight.</p>
</CardContent>
</Card>