Study Guide: Tailwind CSS + shadcn/ui
Tailwind CSS คืออะไร?
Section titled “Tailwind CSS คืออะไร?”ลองเล่นก่อน!
Section titled “ลองเล่นก่อน!”My Project
A short description of the project.
.card {
background: white;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,.1);
overflow: hidden;
}
.card-img {
height: 80px;
background: linear-gradient(135deg,#6366f1,#06b6d4);
}
.card-body { padding: 16px; }
.card-title {
font-size: 16px;
font-weight: 700;
color: #111;
margin: 0 0 6px;
}
.card-desc {
font-size: 12px;
color: #666;
margin: 0 0 12px;
}
.card-btn {
width: 100%;
padding: 8px;
background: #3b82f6;
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
} My Project
A short description of the project.
<div class="bg-white rounded-xl
shadow-sm overflow-hidden">
<div class="h-20
bg-gradient-to-br
from-indigo-500 to-cyan-500">
</div>
<div class="p-4">
<h4 class="text-base font-bold
text-gray-900 mb-1.5">...</h4>
<p class="text-xs text-gray-500
mb-3">...</p>
<button class="w-full py-2
bg-blue-500 text-white
rounded-lg font-semibold">
View
</button>
</div>
</div> ผลลัพธ์เหมือนกัน แต่ Tailwind เขียนตรงใน HTML ไม่ต้องสลับไฟล์
คลิก chip เพื่อเพิ่ม class — กดอีกทีเพื่อเอาออก
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 เปลี่ยน viewport เพื่อดูว่า breakpoint prefix ไหนทำงาน
Dashboard
Welcome back! You have 3 new notifications today.
bg-white dark:bg-gray-900 text-gray-900 dark:text-white text-gray-600 dark:text-gray-400 bg-blue-600 dark:bg-blue-500 bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 สลับ toggle เพื่อดูว่า dark: prefix เปลี่ยน style อย่างไร
Tailwind คือ Utility-first CSS framework — แทนที่จะเขียน CSS แยกไฟล์ เราใส่ class ตรงใน HTML เลย
CSS ปกติ vs Tailwind
Section titled “CSS ปกติ vs Tailwind”<!-- CSS ปกติ: เขียน class แล้วไป style ที่ style.css --><div class="card"> <h2 class="card-title">Hello</h2></div>
<!-- Tailwind: เขียน style ตรงใน class เลย --><div class="p-6 bg-white rounded-xl shadow-md"> <h2 class="text-xl font-bold text-gray-900">Hello</h2></div>Class ที่ใช้บ่อยที่สุด
Section titled “Class ที่ใช้บ่อยที่สุด”Spacing (margin & padding)
Section titled “Spacing (margin & padding)”<!-- p = padding, m = margin --><!-- ตัวเลข: 1=4px, 2=8px, 3=12px, 4=16px, 6=24px, 8=32px --><div class="p-4">padding 16px ทุกด้าน</div><div class="px-6 py-3">padding X=24px, Y=12px</div><div class="mt-4">margin-top 16px</div><div class="mb-8">margin-bottom 32px</div><div class="mx-auto">จัดกลางแนวนอน</div>Typography
Section titled “Typography”<h1 class="text-3xl font-bold text-gray-900">Big Title</h1><p class="text-sm text-gray-500 leading-relaxed"> Small text with relaxed line height</p><span class="text-xs font-medium text-blue-600 uppercase tracking-wider"> Label</span>p-2 8px p-4 16px p-8 32px Colors
Section titled “Colors”<!-- text color --><p class="text-gray-900">เข้ม</p><p class="text-gray-500">กลาง</p><p class="text-blue-600">สีน้ำเงิน</p>
<!-- background --><div class="bg-white">พื้นขาว</div><div class="bg-blue-50">พื้นน้ำเงินอ่อน</div><div class="bg-gray-900">พื้นเข้ม</div>
<!-- opacity --><div class="bg-blue-500/20">น้ำเงินจาง 20%</div>Layout ด้วย Flexbox & Grid
Section titled “Layout ด้วย Flexbox & Grid”<!-- Flexbox --><div class="flex items-center justify-between gap-4"> <span>Left</span> <span>Right</span></div>
<!-- จัดกลางจอ --><div class="flex items-center justify-center min-h-screen"> <h1>Centered</h1></div>
<!-- Grid 3 columns --><div class="grid grid-cols-1 md:grid-cols-3 gap-6"> <div>Card 1</div> <div>Card 2</div> <div>Card 3</div></div>flex items-center gap-4 grid grid-cols-3 gap-4 Border & Shadow
Section titled “Border & Shadow”<div class="border border-gray-200 rounded-lg">มีขอบ</div><div class="rounded-xl shadow-md">มุมมนกับเงา</div><div class="rounded-full">วงกลม</div><div class="border-b border-gray-100">เส้นล่าง</div>Responsive Design ด้วย Tailwind
Section titled “Responsive Design ด้วย Tailwind”Tailwind ใช้ prefix สำหรับ breakpoint — mobile-first
| Prefix | ขนาดจอ | ตัวอย่าง |
|---|---|---|
| (ไม่ใส่) | ทุกขนาด (mobile) | text-sm |
sm: | 640px+ | sm:text-base |
md: | 768px+ | md:grid-cols-2 |
lg: | 1024px+ | lg:grid-cols-3 |
xl: | 1280px+ | xl:max-w-6xl |
<!-- 1 col บน mobile, 2 col บน tablet, 3 col บน desktop --><div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div class="p-4 bg-white rounded-xl">Card</div> <div class="p-4 bg-white rounded-xl">Card</div> <div class="p-4 bg-white rounded-xl">Card</div></div>
<!-- ซ่อนบน mobile, แสดงบน desktop --><nav class="hidden md:flex gap-4"> <a href="/">Home</a> <a href="/about">About</a></nav> grid-cols-1 md:grid-cols-2 lg:grid-cols-3 Hover, Focus, Transition
Section titled “Hover, Focus, Transition”<!-- hover effect --><button class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition-colors duration-200"> Click Me</button>
<!-- card hover --><div class="p-6 bg-white rounded-xl border border-gray-200 hover:shadow-lg hover:border-blue-300 hover:scale-[1.02] transition-all duration-300"> <h3>Hover Card</h3></div>
<!-- focus ring on input --><input class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Type here..." />Dark Mode ด้วย Tailwind
Section titled “Dark Mode ด้วย Tailwind”<!-- ใช้ dark: prefix --><div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100"> <h1 class="text-2xl font-bold"> Works in both themes! </h1> <p class="text-gray-600 dark:text-gray-400"> This text adapts automatically. </p></div>Dashboard
Welcome back! You have 3 new notifications.
bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 text-gray-600 dark:text-gray-400 shadcn/ui คืออะไร?
Section titled “shadcn/ui คืออะไร?”shadcn/ui คือ component library ที่ให้ copy โค้ดมาใส่โปรเจกต์เรา — ไม่ใช่ npm package แต่เป็นโค้ดที่เราเป็นเจ้าของ 100%
ตัวอย่าง Components
Section titled “ตัวอย่าง Components”// Button<Button variant="default">Primary</Button><Button variant="outline">Outline</Button><Button variant="ghost">Ghost</Button>
// Input<Input placeholder="Email" type="email" />
// Card<Card> <CardHeader> <CardTitle>Dashboard</CardTitle> <CardDescription>Overview of your data</CardDescription> </CardHeader> <CardContent> <p>Content here</p> </CardContent></Card>
// Dialog (Modal)<Dialog> <DialogTrigger asChild> <Button>Open Modal</Button> </DialogTrigger> <DialogContent> <DialogHeader> <DialogTitle>Edit Profile</DialogTitle> </DialogHeader> <p>Modal content here</p> </DialogContent></Dialog>เมื่อไหร่ควรใช้ shadcn/ui?
Section titled “เมื่อไหร่ควรใช้ shadcn/ui?”- ต้องการ UI สวยพร้อมใช้ เร็ว
- ทำ Dashboard, Admin Panel, Form
- ต้องการ components ที่ accessible (รองรับ keyboard, screen reader)
- อยาก customize ได้เต็มที่ (เพราะโค้ดเป็นของเรา)
ตัวอย่าง: สร้าง Card ด้วย Tailwind
Section titled “ตัวอย่าง: สร้าง Card ด้วย Tailwind”<div class="max-w-sm mx-auto"> <div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg overflow-hidden hover:shadow-xl transition-shadow duration-300"> <!-- Image --> <img src="project.jpg" alt="Project" class="w-full h-48 object-cover" />
<!-- Content --> <div class="p-6"> <div class="flex items-center gap-2 mb-3"> <span class="text-xs font-medium text-blue-600 bg-blue-50 dark:text-blue-400 dark:bg-blue-900/30 px-2.5 py-1 rounded-full"> Design </span> <span class="text-xs text-gray-400">3 days ago</span> </div>
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2"> My Project Title </h3> <p class="text-sm text-gray-600 dark:text-gray-400 mb-4 line-clamp-2"> This is a short description of the project that might be long. </p>
<button class="w-full py-2.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-xl transition-colors duration-200"> View Project </button> </div> </div></div>Tailwind Config & Customization
Section titled “Tailwind Config & Customization”Tailwind v4 ใช้ระบบใหม่ — ไม่มี tailwind.config.js แล้ว ใช้ @theme block ใน CSS แทน
การใช้ @theme block
Section titled “การใช้ @theme block”@import "tailwindcss";
@theme { /* Custom Colors */ --color-brand: #6366f1; --color-brand-light: #a5b4fc; --color-brand-dark: #4338ca; --color-surface: #f8fafc; --color-surface-dark: #1e293b;
/* Custom Fonts */ --font-heading: "Inter", sans-serif; --font-body: "Noto Sans Thai", sans-serif;
/* Custom Spacing */ --spacing-18: 4.5rem; /* 72px */ --spacing-88: 22rem; /* 352px */
/* Custom Border Radius */ --radius-card: 1rem; --radius-button: 0.625rem;}ใช้ค่า custom ใน HTML
Section titled “ใช้ค่า custom ใน HTML”<!-- ใช้ custom colors จาก @theme --><div class="bg-brand text-white p-6 rounded-card"> <h2 class="font-heading text-2xl font-bold">Custom Theme</h2> <p class="font-body text-brand-light">สวยงามตาม brand ของเรา</p></div>
<button class="bg-brand hover:bg-brand-dark text-white px-6 py-2 rounded-button transition-colors duration-200"> Brand Button</button>Arbitrary Values
Section titled “Arbitrary Values”เมื่อต้องการค่าที่ไม่มีใน theme — ใช้ วงเล็บก้ามปู []
<!-- arbitrary color --><div class="bg-[#1a1a2e] text-[#e94560]">Custom colors</div>
<!-- arbitrary size --><div class="w-[200px] h-[calc(100vh-64px)]">Custom sizing</div>
<!-- arbitrary font-size --><p class="text-[15px] leading-[1.8]">ขนาดเฉพาะเจาะจง</p>
<!-- arbitrary spacing --><div class="mt-[60px] p-[clamp(1rem,3vw,2rem)]">Responsive spacing</div>Responsive Design Patterns
Section titled “Responsive Design Patterns”Pattern สำเร็จรูปที่ใช้ในงานจริงบ่อยที่สุด
Sidebar Layout (Sidebar + Content)
Section titled “Sidebar Layout (Sidebar + Content)”<div class="flex min-h-screen"> <!-- Sidebar: ซ่อนบน mobile, แสดงบน desktop --> <aside class="hidden lg:flex lg:flex-col lg:w-64 bg-gray-900 text-white p-6"> <h2 class="text-lg font-bold mb-6">Dashboard</h2> <nav class="flex flex-col gap-2"> <a href="#" class="px-3 py-2 rounded-lg bg-gray-800 text-white">Home</a> <a href="#" class="px-3 py-2 rounded-lg hover:bg-gray-800 text-gray-400">Settings</a> <a href="#" class="px-3 py-2 rounded-lg hover:bg-gray-800 text-gray-400">Profile</a> </nav> </aside>
<!-- Content --> <main class="flex-1 p-6 lg:p-10 bg-gray-50"> <h1 class="text-2xl font-bold mb-6">Page Content</h1> <div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6"> <div class="bg-white p-6 rounded-xl shadow-sm">Card 1</div> <div class="bg-white p-6 rounded-xl shadow-sm">Card 2</div> <div class="bg-white p-6 rounded-xl shadow-sm">Card 3</div> </div> </main></div>Sticky Header
Section titled “Sticky Header”<header class="sticky top-0 z-50 bg-white/80 backdrop-blur-md border-b border-gray-200"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div class="flex items-center justify-between h-16"> <!-- Logo --> <a href="/" class="text-xl font-bold text-gray-900">Logo</a>
<!-- Desktop Nav --> <nav class="hidden md:flex items-center gap-6"> <a href="#" class="text-sm text-gray-600 hover:text-gray-900">Home</a> <a href="#" class="text-sm text-gray-600 hover:text-gray-900">About</a> <a href="#" class="text-sm text-gray-600 hover:text-gray-900">Contact</a> <button class="bg-blue-600 hover:bg-blue-700 text-white text-sm px-4 py-2 rounded-lg transition-colors"> Sign Up </button> </nav>
<!-- Mobile Menu Button --> <button class="md:hidden p-2 text-gray-600" id="menu-toggle"> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/> </svg> </button> </div> </div></header>Mobile Drawer/Menu
Section titled “Mobile Drawer/Menu”<!-- Overlay + Drawer --><div class="fixed inset-0 z-50 lg:hidden"> <!-- Backdrop --> <div class="fixed inset-0 bg-black/50" id="drawer-backdrop"></div>
<!-- Drawer Panel --> <div class="fixed inset-y-0 left-0 w-72 bg-white shadow-xl transform transition-transform duration-300"> <div class="flex items-center justify-between p-4 border-b"> <span class="text-lg font-bold">Menu</span> <button class="p-2 text-gray-500 hover:text-gray-700" id="drawer-close"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/> </svg> </button> </div> <nav class="flex flex-col p-4 gap-1"> <a href="#" class="px-3 py-2 rounded-lg text-gray-700 hover:bg-gray-100">Home</a> <a href="#" class="px-3 py-2 rounded-lg text-gray-700 hover:bg-gray-100">About</a> <a href="#" class="px-3 py-2 rounded-lg text-gray-700 hover:bg-gray-100">Contact</a> </nav> </div></div>Tips: Container & Max-width
Section titled “Tips: Container & Max-width”<!-- container จัดกลาง + responsive padding --><div class="container mx-auto px-4 sm:px-6 lg:px-8"> <p>Content stays centered and readable</p></div>
<!-- max-w ควบคุมความกว้างสูงสุด --><div class="max-w-md mx-auto">Narrow (28rem)</div><div class="max-w-2xl mx-auto">Medium (42rem)</div><div class="max-w-5xl mx-auto">Wide (64rem)</div><div class="max-w-7xl mx-auto">Full layout (80rem)</div>Component Composition
Section titled “Component Composition”Reusable Patterns จาก Tailwind Classes
Section titled “Reusable Patterns จาก Tailwind Classes”แทนที่จะ copy class ยาว ๆ ซ้ำ สร้างเป็น component ใน framework ของเรา
// ซ้ำ class ทุกที่<button class="bg-blue-600 hover:bg-blue-700 text-white font-medium px-4 py-2 rounded-lg transition-colors">Save</button><button class="bg-blue-600 hover:bg-blue-700 text-white font-medium px-4 py-2 rounded-lg transition-colors">Submit</button>
// สร้างเป็น component แทนfunction Button({ children, variant = "primary", size = "md" }) { const base = "font-medium rounded-lg transition-colors"; const variants = { primary: "bg-blue-600 hover:bg-blue-700 text-white", secondary: "bg-gray-200 hover:bg-gray-300 text-gray-800", danger: "bg-red-600 hover:bg-red-700 text-white", ghost: "hover:bg-gray-100 text-gray-700", }; const sizes = { sm: "px-3 py-1.5 text-sm", md: "px-4 py-2 text-sm", lg: "px-6 py-3 text-base", }; return ( <button class={`${base} ${variants[variant]} ${sizes[size]}`}> {children} </button> );}เมื่อไหร่ควรใช้ @apply?
Section titled “เมื่อไหร่ควรใช้ @apply?”/* ใช้ @apply เมื่อ: ซ้ำบ่อยมากและไม่อยู่ใน component framework */.prose a { @apply text-blue-600 underline hover:text-blue-800 transition-colors;}
/* ใช้กับ third-party elements ที่ control ไม่ได้ */.markdown-body h2 { @apply text-2xl font-bold text-gray-900 mt-8 mb-4;}/* ไม่ควรใช้ @apply สร้าง component class -- ใช้ JSX component แทน */.btn-primary { @apply bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg;}Design Token Approach — CSS Variables + Tailwind
Section titled “Design Token Approach — CSS Variables + Tailwind”/* กำหนดค่าตรงกลาง */:root { --color-primary: #6366f1; --color-primary-hover: #4f46e5; --radius-default: 0.5rem; --shadow-card: 0 1px 3px rgba(0,0,0,0.1);}
.dark { --color-primary: #818cf8; --color-primary-hover: #a5b4fc;}<!-- ใช้ CSS variables เป็น arbitrary values --><button class="bg-[var(--color-primary)] hover:bg-[var(--color-primary-hover)] text-white px-4 py-2 rounded-[var(--radius-default)]"> Token Button</button>
<div class="bg-white shadow-[var(--shadow-card)] rounded-[var(--radius-default)] p-6"> Token Card</div>ตัวอย่าง: Button Variants จาก Tailwind
Section titled “ตัวอย่าง: Button Variants จาก Tailwind”<!-- Primary --><button class="bg-blue-600 hover:bg-blue-700 text-white font-medium px-4 py-2 rounded-lg transition-colors"> Primary</button>
<!-- Secondary --><button class="bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium px-4 py-2 rounded-lg transition-colors"> Secondary</button>
<!-- Outline --><button class="border border-gray-300 hover:bg-gray-50 text-gray-700 font-medium px-4 py-2 rounded-lg transition-colors"> Outline</button>
<!-- Ghost --><button class="hover:bg-gray-100 text-gray-600 font-medium px-4 py-2 rounded-lg transition-colors"> Ghost</button>
<!-- Destructive --><button class="bg-red-600 hover:bg-red-700 text-white font-medium px-4 py-2 rounded-lg transition-colors"> Delete</button>Overview of your data with key metrics and insights.
Best Practices & Style Guide
Section titled “Best Practices & Style Guide”Class Ordering Convention
Section titled “Class Ordering Convention”เรียง class ตามลำดับนี้เพื่อให้อ่านง่าย:
| ลำดับ | หมวด | ตัวอย่าง |
|---|---|---|
| 1 | Layout | flex, grid, block, hidden, relative |
| 2 | Positioning | absolute, top-0, z-10 |
| 3 | Spacing | p-4, m-2, gap-6 |
| 4 | Sizing | w-full, h-16, max-w-md |
| 5 | Typography | text-sm, font-bold, leading-relaxed |
| 6 | Colors | bg-white, text-gray-900, border-gray-200 |
| 7 | Effects | shadow-md, opacity-50, rounded-lg |
| 8 | Transitions | transition-colors, duration-200 |
| 9 | States | hover:bg-blue-700, focus:ring-2 |
| 10 | Responsive | md:flex, lg:grid-cols-3 |
Do/Don’t Comparison
Section titled “Do/Don’t Comparison”1. Class Ordering
Section titled “1. Class Ordering”<!-- Don't: สลับหมวดมั่ว อ่านยาก --><div class="text-white rounded-lg hover:bg-blue-700 flex p-4 bg-blue-600 gap-4 items-center">
<!-- Do: เรียงตามหมวด layout > spacing > typography > colors > effects > states --><div class="flex items-center gap-4 p-4 text-white bg-blue-600 rounded-lg hover:bg-blue-700">2. Responsive Approach
Section titled “2. Responsive Approach”<!-- Don't: เขียน desktop-first แล้วซ่อนด้วย max-* (ไม่ใช่ Tailwind way) --><div class="grid grid-cols-3 max-md:grid-cols-1">
<!-- Do: mobile-first เริ่มจากเล็กแล้วเพิ่ม breakpoint ขึ้นไป --><div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">3. Avoiding !important
Section titled “3. Avoiding !important”<!-- Don't: ใช้ ! (important) เพื่อ override --><p class="!text-red-500">Error message</p>
<!-- Do: ใช้ specificity ที่ถูกต้อง หรือ restructure HTML --><p class="text-red-500 font-medium">Error message</p>4. Custom CSS vs Tailwind
Section titled “4. Custom CSS vs Tailwind”/* Don't: เขียน CSS ยาวเมื่อ Tailwind ทำได้ */.custom-card { display: flex; padding: 1.5rem; background-color: white; border-radius: 0.75rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1);}<!-- Do: ใช้ Tailwind classes ตรง ๆ --><div class="flex p-6 bg-white rounded-xl shadow-sm">/* เขียน custom CSS เมื่อ: animation ซับซ้อน, pseudo-elements, หรือ styles ที่ Tailwind ไม่รองรับ */@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); }}.animate-float { animation: float 3s ease-in-out infinite;}File Structure สำหรับ Tailwind Projects
Section titled “File Structure สำหรับ Tailwind Projects”src/├── app.css <- @import "tailwindcss" + @theme block├── components/│ ├── Button.jsx <- component ที่รวม Tailwind classes│ ├── Card.jsx│ └── Layout.jsx├── styles/│ ├── tokens.css <- CSS variables / design tokens│ └── animations.css <- custom @keyframes ที่ Tailwind ไม่มี└── pages/ ├── Home.jsx └── Dashboard.jsxลองทำเอง
Section titled “ลองทำเอง”-
สร้าง Navbar — logo ซ้าย, links ขวา, responsive (hamburger บน mobile)
-
สร้าง Card Component — รูป, title, description, button พร้อม hover effect
-
สร้าง Sidebar Layout — sidebar ซ้าย + content ขวา ใช้ Flexbox
-
ทำ Data Table — ตารางที่มี header, rows, border, hover state
-
ลอง Dark Mode — ใช้
dark:prefix ให้ทุก component สลับ theme ได้