Day 2 建好了 React + TypeScript + Vite 的基本環境
在開始第一個component之前---
shadcn/ui 到底是什麼?
開官網,可以看到 Button、Input、Dialog、Tabs、Select...各種常見元件,看起來和一般 Component Library 沒什麼不同
官方對自己的定位卻很有意思:
This is not a component library. It is how you build your component library.
shadcn/ui 並不把自己定位成傳統的 Component Library,而是一套用來建立自己 Component Library 的方式。
平常:npm install some-ui-library
接著從套件中 import 需要的 Component:
import { Button } from "some-ui-library"
function App() {
return <Button>儲存</Button>
}
Component 的主要實作由 Library 維護
但當客製化需求越來越多時,有時候也會開始出現:
Override Style
↓
再包一層 Component
↓
再補一些 CSS
↓
為了特殊需求再包一層
shadcn/ui 最核心的差異之一,就是 Open Code
例如加入一個 Button:
npx shadcn@latest add button
它並不是要我們之後這樣使用:
import { Button } from "shadcn-ui"
而是直接把 Button 的 Component Code 加進自己的專案。
之後使用的是:
import { Button } from "@/components/ui/button"
概念變成:
shadcn Registry
│
▼
add button
│
▼
我的 Project
│
└─ components/
└─ ui/
└─ button.tsx
button.tsx 就在自己的專案裡。
可以直接打開它、閱讀它,也可以修改它。
所以 shadcn/ui 和一般 Component Library 最大的差異之一,可以簡單理解成:
不是只把 Component 給你「使用」,而是把 Component 的 Code 交給你。
如果看過比較早期的 shadcn/ui 文章,可能常常會看到:
shadcn/ui 的 Component 是建立在 Radix UI 上。
這在早期確實是 shadcn/ui 很重要的架構。
不過現在已經不只有 Radix UI。
目前 shadcn/ui 支援三種 Component Base:
shadcn/ui
│
┌──────────┼──────────┐
▼ ▼ ▼
Base UI Radix React Aria
2026 年 7 月開始,新建立的 shadcn/ui Project 預設使用 Base UI。
Radix 仍然持續支援,也可以選擇 React Aria。
它們負責的事情和我們看到的視覺樣式並不完全相同
Keyboard Interaction
Focus Management
ARIA Attributes
Component State
Interaction Behavior
這些底層行為可以由 Base UI、Radix 或 React Aria 等 Component Base 提供,再由 shadcn/ui 在上面建立一致的 Component API 與 Style!
但當 Component Code 已經進到自己的專案,而且開始修改
這時候它就不再只是「shadcn/ui 的 Button」
自己也開始對這份 Code 負責。
例如原本 Component 已經處理好 Focus Style,客製化時卻直接寫:
button:focus {
outline: none;
}
那最後鍵盤使用者看不到 Focus,可不能再回頭怪 shadcn/ui~
同樣地,上游 Component 有新的修改時,也不一定能像一般 npm package 一樣,更新版本就直接結束。
控制權變多,Ownership 也跟著變多。
這點對要建立自己的 UI Kit 來說,反而是一件需要先知道的事情。
和一般 Component Library 比較看看
整理一下目前理解的差異:
| 一般 Component Library | shadcn/ui | |
|---|---|---|
| Component Code | 主要存在 Package 中 | Source Code 加入自己的 Project |
| 使用方式 | 從 Package Import | 從自己的 Components Import |
| 客製化 | Props、Theme、Override 等 | 可以直接修改 Source |
| 更新方式 | 跟著 Package Version | 需要處理自己的 Code 與上游變更 |
| 控制權 | 依 Library 提供的 API 而定 | 高 |
| 維護責任 | Library 維護主要實作 | 自己承擔更多 Ownership |
| 主要定位 | 使用現成元件庫 | 建立自己 Component Library 的基礎 |
所以兩種方式並沒有誰一定比較好。
如果需求和某套 Component Library 非常接近,直接使用成熟的 Library,反而可以省下大量維護成本。
而 shadcn/ui 適合的是另一種需求:
需要一個成熟的起點,但同時希望 Component 最後真正屬於自己的 Design System。
今天還是沒有真正做出任何 Component:)
但至少搞懂了一件很重要的事情:
從 shadcn/ui 取得一個 Component 的起點,再慢慢把它變成自己的 UI Kit。
而現在下一個問題就很直接了。
當執行:
npx shadcn@latest add button
到底有哪些東西被加進 Project?
Button 裡面有哪些 Dependencies?
Variant 怎麼處理?
Style 又放在哪裡?
下一篇就真的抓一顆 Button 進來拆開看看。
Day 4: 拆開 shadcn/ui Button:一顆元件裡到底有什麼?