shadcn/ui:不是 npm 装的 UI 库(拷贝 component 模式)

起因

React UI 库选择困难:

  • Material UI:很全 + 重 + 偏 google look
  • Chakra UI:现代 + 灵活但 bundle 大
  • Ant Design:业务向,复杂表单强
  • Radix UI:unstyled headless
  • Tailwind UI:付费 component

每个都是"npm install 进项目,按 props 用"。
痛点:

  • 改 design 难(要覆盖默认 style)
  • 升级 lib 版本可能 break style
  • bundle 总是吃满(你只用 button 但 import 全 lib)

shadcn/ui 提出不同模式:copy component code 进项目
不是 library,是 component template + Radix 底层。

加 component

npx shadcn@latest init
# 配置 tailwind / 颜色主题

npx shadcn@latest add button
# 把 Button 源码 copy 到 components/ui/button.tsx
import { Button } from '@/components/ui/button';

<Button variant="default">Click</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline" size="sm">Cancel</Button>

UI 跟 Tailwind UI 类似(基于 Tailwind class)。

改 component 是 yours

npx shadcn@latest add card

文件 components/ui/card.tsx 现在是你的。
要改 padding / 圆角 / 加 prop → 直接改源码。
没 lib 升级问题(没 lib)。

模式核心

Radix UI (headless, accessible)
   +
Tailwind CSS (styling)
   +
你 own 的 code
   =
shadcn/ui
  • Radix 提供 a11y / behavior(focus trap / aria 等)
  • Tailwind 提供 styling
  • 你拥有源码 + 修改自由

优势

  • 零 lock-in:lib 没了你 code 不挂
  • 改 design 直接改 file
  • bundle 只含你用的 component(tree-shake 友好)
  • TS first-class
  • 跟现代 stack(Next.js / Vite / Astro)天然 fit

劣势

  • 不是 install 即用(每 component 要 add + 看 code)
  • 升级要手动(lib 出新版要 copy 新 source)
  • 设计语言比 Material 单调(neutral 风格,要自己丰富)

完整 setup

# Next.js + Tailwind 项目
npx shadcn@latest init

# 装常用
npx shadcn@latest add button card input label dialog dropdown-menu sheet

生成:

components/ui/
  button.tsx
  card.tsx
  dialog.tsx
  ...
lib/utils.ts        # cn() helper

cn() 是 clsx + tailwind-merge 包装,让 className 智能合并:

<Button className={cn('w-full', isLoading && 'opacity-50', className)}>

form 模式

shadcn + react-hook-form + zod:

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form';
import { Input } from '@/components/ui/input';

const schema = z.object({
    email: z.string().email(),
});

function MyForm() {
    const form = useForm({ resolver: zodResolver(schema) });

    return (
        <Form {...form}>
            <form onSubmit={form.handleSubmit(console.log)}>
                <FormField
                    control={form.control}
                    name="email"
                    render={({ field }) => (
                        <FormItem>
                            <FormLabel>Email</FormLabel>
                            <FormControl>
                                <Input {...field} />
                            </FormControl>
                            <FormMessage />
                        </FormItem>
                    )}
                />
                <Button type="submit">Submit</Button>
            </form>
        </Form>
    );
}

template 嗦但极灵活 + a11y 完整 + validation 自动。

theme

globals.css

@layer base {
    :root {
        --background: 0 0% 100%;
        --foreground: 222.2 84% 4.9%;
        --primary: 222.2 47.4% 11.2%;
        --primary-foreground: 210 40% 98%;
        /* ... */
    }
    .dark {
        --background: 222.2 84% 4.9%;
        --foreground: 210 40% 98%;
        /* ... */
    }
}

CSS variable 驱动主题。dark mode 加 class="dark" on root。
改 brand color:改 --primary

sonner / vaul 等

shadcn 推荐组合的几个:

  • sonner:toast notification
  • vaul:bottom sheet (mobile-style drawer)
  • cmdk:command palette
  • react-day-picker:date picker

都是高质量 headless lib,shadcn add 帮你 scaffold 集成。

v0 / 自动生成 UI

v0.dev(Vercel)用 LLM 生成 shadcn/ui-based React component:

prompt: "user profile card with avatar, name, bio, and follow button"
→ 生成 component code 用 shadcn pieces

新 component prototype 1 分钟出。
之后人 review + 调整。

与 Material / Chakra 对比

shadcn Material UI Chakra
copy code npm install npm install
改 design 改 code override theme / sx override theme
学习曲线 中(要懂 Tailwind) 高(API 大)
bundle tree-shake 极好
设计语言 minimal neutral google material 现代
适合 custom design / 中型项目 企业产品 通用

我 2024+ 项目 100% shadcn。
老 Material 项目维持。

跟 Tailwind UI 对比

Tailwind UI(付费):

  • 设计精良,付费许可
  • 复制 HTML 进项目(不分 component)

shadcn:

  • 免费
  • React component(不只是 HTML)
  • 跟 Radix 集成(a11y)

如果钱不是问题且要顶级设计 → Tailwind UI 块 + shadcn 组件 混用。

何时不用

  • 不用 React → shadcn 是 React-only(但 Svelte/Vue 有 community port)
  • 不用 Tailwind → 不适合(核心是 Tailwind class)
  • 极简项目(landing page)→ Tailwind 直接写 HTML 够

真实 case

新项目 admin dashboard:

  • 1 周 setup shadcn + 10+ component
  • 0 设计稿,直接 v0 生成 + 微调
  • bundle 200 KB(vs Material 类似项目 600 KB+)
  • 想改 button radius 全局 → 改 --radius CSS var

迭代速度 + 灵活性大幅提升。

踩过的坑

  1. 不识别相对路径:shadcn 默认用 @/components/ui/... alias。
    要 tsconfig + vite config 配 alias。

  2. 冲突 className<Button className="w-full bg-red-500"> 跟内
    建 variant 冲突。cn() + tailwind-merge 解决。

  3. 暗色模式切换闪烁:SSR 时 server 不知道用户 prefer。Next.js
    用 next-themes 处理 hydration。

  4. lib 更新没拉新:shadcn 出新 version Button → 你的没自动升。
    手动 npx shadcn add button --overwrite 或者 diff merge。

  5. 设计简陋:default 风格中性 → 看起来朴素。要加品牌色 / 图标 /
    插图才"鲜活"。

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。