shadcn/ui: ngày tôi thôi đánh nhau với thư viện UI

4 phút đọc
shadcn-ui/ui

Tôi có một lời thú nhận. Nhiều năm liền tôi chọn thư viện UI kiểu như chọn tiệm cắt tóc ở thành phố lạ: đọc hai cái review, bước vào, cầu trời. Nút bấm nhìn sai thì tại mình. Hệ thống theme đọc như nhật ký người khác thì chắc mình chưa đủ giỏi.

Rồi một buổi chiều tôi thấy tweet về shadcn/ui. Ý tưởng đơn giản tới mức tôi suýt lướt qua: component nằm trong repo của bạn, không phải trong node_modules. Bạn copy. Bạn sở hữu. Hết.

Tôi nghĩ: cái này làm sao mà chạy được. Một tuần sau tôi đã dùng nó trên production.

Khoảnh khắc mọi thứ vỡ lẽ

Lần đầu chạy CLI, nó bình thường tới mức hơi hụt hẫng.

npx shadcn@latest init
npx shadcn@latest add button card dialog

File xuất hiện trong project. Không phải bundle đã biên dịch. Không phải mớ code nén khó đọc. Là file TypeScript thật, class Tailwind đọc được lúc 2 giờ sáng mà không cần nheo mắt. Tôi mở component Button, hiểu trong ba mươi giây, đổi border radius, rồi tiếp tục sống.

Chuyện đó chưa bao giờ xảy ra với Chakra. Với Chakra tôi mất cả tiếng đọc docs về theme, tự thuyết phục mình hiểu API extendTheme, rồi ngồi nhìn thay đổi bị ghi đè âm thầm bởi style precedence nội bộ mà tôi không hề đăng ký.

Vì sao người ta thật sự star cái repo này

Một trăm nghìn star là con số kỳ lạ. Người ta không star file README. Người ta star sự nhẹ nhõm.

Tôi nghĩ họ nhẹ nhõm vì:

Thế giới cũshadcn/ui làm khác thế nào
Upgrade thư viện, cầu nguyện không vỡ gìBạn tự quyết lúc nào đổi file của mình
Theme cần bằng tiến sĩ về mental model của thư việnToken nằm ngay cạnh component
Debug là đọc source map đã biên dịchBreakpoint dừng đúng trên code của bạn

Cốt lõi không phải “không phụ thuộc.” Mà là ít bí mật hơn. Ít chỗ mà giao diện app là quyết định biên dịch của người khác mà bạn không thể kiểm tra nếu không có decompiler.

import { Button } from "@/components/ui/button";

export function NutGui() {
  return <Button variant="outline">Ship thôi</Button>;
}

Cái đường import đó là project của bạn. Không phải package. Không phải lời cầu nguyện.

Phần mà ít ai nói

Có cái giá. Bạn giờ sở hữu đống code này. Khi Radix đẩy breaking change lên accessibility primitives bên dưới, không ai gửi PR cho bạn. Bạn tự cập nhật, hoặc không. Với developer solo thì ổn. Với đội hai mươi người, cần có ai đó để ý.

Tôi từng thấy team copy component một lần rồi không đụng lại cả năm. Code chạy, nhưng từ từ trôi xa khỏi cải tiến upstream. Đó là đánh đổi, không phải lỗi. Nhưng bạn nên biết trước khi nhảy vào.

Một chuyện nữa: hệ sinh thái quanh shadcn/ui đang ồn ào. Starter kit, template trả phí, huy hiệu “tương thích shadcn” trên mọi thư viện mới. Ồn ào là lời khen — chỉ có thứ đáng lấy cắp mới đáng tranh cãi — nhưng bạn cũng sẽ phải lội qua nhiều quảng cáo để tìm thứ thật sự hữu ích.

Tóm lại

shadcn/ui không biến tôi thành designer giỏi hơn. Nó giúp tôi thôi đánh nhau với công cụ. Khoảng cách từ “tôi muốn nút này trông khác” đến “nút này trông khác rồi” rút từ bốn mươi lăm phút khảo cổ theme xuống ba phút sửa file mình sở hữu.

Nếu bạn từng ngồi nhìn ThemeProvider tự hỏi tại sao màu viền không chịu đổi, bạn đã hiểu vì sao repo này có sáu chữ số star. Không phải ma thuật. Là ngược lại của ma thuật. Là code của bạn, trong repo của bạn, làm đúng điều bạn bảo nó làm.

Chuyện đó đáng lẽ không nên gọi là cách mạng. Nhưng nó là vậy.


shadcn-ui/ui · MIT · 110k stars · docs