![]()
Shadcn là gì mà khiến dân dev xôn xao?
Hồi đầu năm 2023, mình còn nhớ như in cái cảm giác "chán ngán" khi mở dự án mới và biết rằng sắp phải đối mặt với một đống UI library nặng nề, khó tùy chỉnh. Rồi bỗng dưng shadcn xuất hiện như một làn gió mới.
Không phải là thư viện, cũng chẳng phải framework – shadcn tự nhận mình là "tập hợp các component có thể tái sử dụng mà bạn copy-paste vào dự án". Nghe có vẻ lạ đúng không?Một thư viện UI mà không cài qua npm? Đó chính là điểm khác biệt làm nên tên tuổi của shadcn.Hãy nhìn vào con số: chỉ sau 19 tháng, repo shadcn đã đạt gần 70.000 stars. So với Material UI (khoảng 92.000 stars sau nhiều năm), tốc độ tăng trưởng này thực sự ấn tượng.Vậy điều gì đã tạo nên sức hút đó?| Đặc điểm | Thư viện truyền thống (Material UI) | Shadcn |
|---|---|---|
| Cách cài đặt | npm install | Copy-paste hoặc CLI |
| Kích thước project | Nặng, nhiều component không dùng | Chỉ lấy component cần |
| Tùy chỉnh | Phức tạp, override CSS | Dễ dàng, sửa trực tiếp code |
| Phụ thuộc | Nhiều dependency | Tối thiểu |
Cái hay của shadcn nằm ở triết lý "headless" kết hợp với Tailwind CSS. Nó dùng Radix UI – một thư viện headless tập trung vào accessibility – làm nền tảng, rồi "khoác áo" cho các component bằng Tailwind.
Kết quả? Bạn có component đẹp, chuẩn accessibility, và quan trọng nhất: toàn quyền kiểm soát code.Sau khi hiểu shadcn là gì, chắc bạn cũng tò mò: làm sao để xây dựng module tùy chỉnh với nó? Hãy cùng mình đi vào phần thực chiến.Chuẩn bị môi trường Đừng để "bài vở" làm khó bạn
Trước khi bắt tay vào code, mình muốn kể một câu chuyện nhỏ. Có lần mình mất gần 2 tiếng để config shadcn với Docusaurus, chỉ vì không đọc kỹ tài liệu.
Đúng là "dốt đặc còn hơn thông minh" mà không chịu học hỏi. Thực tế, việc thiết lập môi trường cho shadcn khá đơn giản nếu bạn làm đúng trình tự.Dưới đây là các bước mình đã rút ra sau nhiều lần "vấp ngã":Bước 1: Khởi tạo dự án React/Vite/Next.js
Mình khuyên bạn dùng Vite cho dự án nhỏ, Next.js cho dự án lớn. Cả hai đều giúp shadcn tốt.
Bước 2: Cài đặt Tailwind CSSbash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Bước 3: Config shadcn
bash
npx shadcn@latest init
Lúc này hệ thống sẽ hỏi bạn vài câu để tạo file components.json. Đừng vội "next" qua, hãy đọc kỹ:
| Câu hỏi | Gợi ý trả lời |
|---|---|
| Which style would you like to use? | Default (New York) |
| Which color would you like to use? | Neutral hoặc Zinc |
| Where is your global CSS file? | src/index.css |
| Do you want to use CSS variables? | Yes |
| Where is your tailwind.config.js? | tailwind.config.js |
| Configure the import alias for components? | @/components |
| Configure the import alias for utils? | @/lib/utils |
Mẹo nhỏ: Nên chọn CSS variables để dễ dàng đổi theme sau này. Nếu bạn chọn "No", shadcn sẽ dùng class-based, khá bất tiện khi muốn chuyển đổi sáng/tối.
Sau khi init xong, bạn sẽ thấy thư mụcsrc/components/ui và src/lib/utils.ts được tạo tự động. Nếu không, hãy kiểm tra lại config.OK, môi trường đã sẵn sàng. Giờ đến lúc "phiêu" với việc tạo module tùy chỉnh.
Cách tạo module tùy chỉnh Copy-paste hay CLI?
Đây là câu hỏi mà nhiều bạn mới hỏi mình nhất. Câu trả lời: tùy vào tình huống.
Hãy tưởng tượng bạn đang làm việc trong nhóm 5 người, ai cũng cần dùng component Button. Dùng CLI sẽ đồng bộ được version.Còn nếu bạn solo project, copy-paste nhanh hơn nhiều.Cách 1 Dùng CLI (Khuyên dùng cho team)
bash
npx shadcn@latest add button
npx shadcn@latest add card
npx shadcn@latest add dialog
Mỗi lần chạy lệnh, shadcn sẽ:
- Tải component vào
src/components/ui/ - Cập nhật dependencies nếu cần
- Tích hợp với tailwind.config.js
Mình từng thử add 10 component liên tiếp, mất khoảng 2 phút. So với việc tự viết từ đầu mất 2-3 giờ, đây là con số đáng để suy nghĩ.
Cách 2 Copy-paste (Dành cho dự án đặc thù)
Một số framework như Docusaurus không giúp CLI shadcn. Lúc này bạn phải copy-paste thủ công.
Các bước:- Vào trang https://ui.shadcn.com
- Chọn component mong muốn
- Click "Copy" code
- Tạo file
.tsxtrongsrc/components/ui/ - Paste code và điều chỉnh import path
Ví dụ với Button component:
tsx
// src/components/ui/button.tsx
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
Lưu ý: Bạn cần cài thêm class-variance-authority và @radix-ui/react-slot nếu chưa có.
So sánh thời gian thực tế
| Phương pháp | Thời gian cho 1 component | Phù hợp |
|---|---|---|
| CLI | 10-15 giây | Team, dự án React/Next |
| Copy-paste | 2-3 phút | Docusaurus, Gatsby |
| Tự viết từ đầu | 2-4 giờ | Dự án đặc thù cao |
Sau khi có component, bước tiếp theo là tùy chỉnh chúng. Đây mới là phần "chất" nhất.
Tùy chỉnh component Khi "chuẩn" chưa đủ, cần "độc"
Mình từng gặp một bạn dev than phiền: "Em dùng shadcn mà sao thấy giống hệt mấy trang demo, chán quá". Đúng, nếu bạn chỉ dùng nguyên bản, ai cũng giống ai.
Nhưng sức mạnh của shadcn nằm ở khả năng tùy chỉnh.Cấu trúc theme của shadcn
Shadcn dùng CSS variables để quản lý màu sắc. Nhìn vào file globals.css bạn sẽ thấy:
css
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
}
Mỗi biến là một giá trị HSL (Hue, Saturation, Lightness). Để đổi màu chủ đạo, bạn chỉ cần sửa giá trị Hue.
Ví dụ: Muốn theme màu xanh lá, đổi--primary: 142 76% 36% (màu xanh lá chuẩn).
Cách tạo module tùy chỉnh từ component có sẵn
Giả sử bạn muốn tạo một Card có hiệu ứng hover đặc biệt. Đừng sửa trực tiếp file card.tsx – hãy tạo wrapper:
```tsx // src/components/custom/CustomCard.tsx import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
export function CustomCard({ title, children }) {
return (
Cách này giúp bạn giữ nguyên component gốc, dễ dàng update sau này.
Tạo module mới từ Radix + Tailwind
Đôi khi shadcn chưa có component bạn cần. Lúc này hãy tự build dựa trên Radix.
Ví dụ: Tạo một Tooltip component:```tsx // src/components/ui/tooltip.tsx import * as TooltipPrimitive from "@radix-ui/react-tooltip" import { cn } from "@/lib/utils"
const TooltipProvider = TooltipPrimitive.Provider const Tooltip = TooltipPrimitive.Root const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipContent = React.forwardRef<
React.ElementRef
(({ className, sideOffset = 4, ...props }, ref) => (
))
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } ```
Mất khoảng 15 phút để viết, nhưng bạn đã có một component chuẩn accessibility, style theo theme shadcn.
Bảng tổng hợp cách tùy chỉnh
| Mục đích | Cách làm | Mức độ khó |
|---|---|---|
| Đổi màu theme | Sửa CSS variables | Dễ |
| Thêm hiệu ứng | Dùng Tailwind classes | Dễ |
| Mở rộng component | Tạo wrapper | Trung bình |
| Tạo component mới | Dùng Radix + Tailwind | Khó |
Tới đây, mình tin bạn đã có thể tự tin tạo module tùy chỉnh. Nhưng còn một vấn đề: làm sao để quản lý nhiều module mà không rối?
Quản lý và tối ưu module Bí kíp từ thực tế
Sau 10 năm trong nghề, mình đúc kết được vài nguyên tắc vàng khi làm việc với shadcn.
Nguyên tắc 1 Phân loại thư mục rõ ràng
src/
components/
ui/ # Component gốc từ shadcn
custom/ # Module tùy chỉnh
features/ # Module theo tính năng
layouts/ # Layout component
Nguyên tắc 2 Dùng barrel exports
Tạo file index.ts trong mỗi thư mục để export gọn gàng:
ts
// src/components/ui/index.ts
export { Button } from "./button"
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from "./card"
Khi import, chỉ cần:
tsx
import { Button, Card } from "@/components/ui"
Nguyên tắc 3 Tối ưu bundle size
Shadcn vốn đã nhẹ, nhưng nếu bạn dùng nhiều component từ Radix, hãy chú ý:
| Component | Kích thước (minified) | Khuyên dùng |
|---|---|---|
| Button | 1.2 KB | Luôn dùng |
| Card | 0.8 KB | Luôn dùng |
| Dialog | 4.5 KB | Khi cần modal |
| Dropdown Menu | 6.2 KB | Khi cần menu |
| Data Table | 15 KB | Chỉ khi cần bảng phức tạp |
Mẹo: Chỉ add component khi thực sự cần, đừng add sẵn "để đó sau".
Nguyên tắc 4 Version control
Khi update shadcn lên version mới, đừng chạy CLI lại toàn bộ. Hãy:
- Check changelog xem component nào thay đổi
- Chỉ update những component cần thiết
- So sánh code cũ và mới trước khi merge
Kết luận Shadcn có đáng để bạn đầu tư?
Nhìn lại hành trình từ lúc shadcn ra mắt đến nay, mình thấy đây không chỉ là một công cụ, mà còn là một cách tiếp cận mới trong thiết kế UI. Thay vì phụ thuộc vào thư viện đóng gói sẵn, bạn lấy quyền kiểm soát vào tay mình.
Con số 70.000 stars không phải là ngẫu nhiên. Nó phản ánh nhu cầu thực sự của cộng đồng: một giải pháp UI vừa nhanh, vừa linh hoạt, vừa không kèm theo "hàng đống code thừa".Nếu bạn đang phân vân giữa shadcn và các thư viện khác, hãy thử nghiệm với một dự án nhỏ. Mình cá là sau đó bạn sẽ không muốn quay lại cách cũ đâu.Còn nếu bạn đã dùng shadcn rồi, hãy chia sẻ kinh nghiệm của mình ở phần bình luận. Mình rất muốn học hỏi thêm từ cộng đồng.Chúc bạn code vui vẻ và đừng quên: "Copy-paste không có gì xấu, miễn là bạn hiểu mình đang copy cái gì".