Component Design System
สร้าง reusable UI components ด้วย Tailwind CSS และ class-variance-authority
ผมใช้ shadcn/ui เป็นรากฐานสำหรับ component library ต่างจาก component libraries ทั่วไป shadcn/ui ให้ source code มา — หมายความว่าควบคุม styling และ behavior ได้เต็มที่ Components สร้างด้วย Radix UI primitives (สำหรับ accessibility), style ด้วย Tailwind CSS และใช้ class-variance-authority (CVA) สำหรับจัดการ variants รูปแบบนี้ช่วยให้สร้าง components ที่สม่ำเสมอพร้อม variants (size, color, state) ในขณะที่ API ยังง่ายและ type-safe
ผมใช้ shadcn/ui + Radix UI + CVA สำหรับ accessible และ customizable components คุณสามารถได้ผลลัพธ์คล้ายกันด้วย Material UI, Chakra UI, Ant Design หรือสร้างเองด้วย Headless UI รูปแบบ variant ที่แสดง (ใช้ CVA) สามารถ implement ด้วย Tailwind classes ปกติ, CSS Modules หรือ styled-components ก็ได้
วิธีการทำงาน
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.
คุณสมบัติหลัก
- •Variant-based component API
- •Composable และ reusable patterns
- •Accessible components (Radix UI)
- •Type-safe props ด้วย TypeScript
- •Consistent design tokens
ตัวอย่างการใช้งาน
ปุ่ม
<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>
การ์ด
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>