# Shadcn

> 管理 shadcn 组件和项目——添加、搜索、修复、调试、样式化和组合 UI。提供项目上下文、组件文档和使用示例。适用于使用 shadcn/ui、组件注册表 (registries)、预设 (presets)、--preset 代码或任何包含 components.json 文件的项目。也可由 "shadcn init"、"create an app with --preset" 或 "switch to --preset" 触发。

- Skill: `agent-skills/shadcn` (Agent Skill, multi-file: 13 files)
- Install (CLI): `npx skillmds@latest add agent-skills/shadcn`
- Raw SKILL.md: https://api.skillmd.com/api/skills/agent-skills/shadcn/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: agent-skills (https://skillmd.com/u/agent-skills)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/agent-skills/shadcn

---


# shadcn/ui

一个用于构建 UI、组件和设计系统的框架。组件通过 CLI 以源码形式添加到用户的项目中。

> **重要提示：** 请使用项目的包运行器执行所有 CLI 命令：`npx shadcn@latest`、`pnpm dlx shadcn@latest` 或 `bunx --bun shadcn@latest` —— 取决于项目的 `packageManager`。以下示例使用 `npx shadcn@latest`，但在实际操作中请替换为项目正确的运行器。

## 当前项目上下文

```json
!`npx shadcn@latest info --json`
```

上面的 JSON 包含了项目配置和已安装的组件。使用 `npx shadcn@latest docs <component>` 获取任何组件的文档和示例 URL。

## 原则

1. **优先使用现有组件。** 在编写自定义 UI 之前，先运行 `npx shadcn@latest search` 检查注册表。同时也检查社区注册表。
2. **组合而非重造。** 设置页面 = Tabs + Card + 表单控件。仪表板 = Sidebar + Card + Chart + Table。
3. **优先使用内置变体而非自定义样式。** 如 `variant="outline"`, `size="sm"` 等。
4. **使用语义化颜色。** 如 `bg-primary`, `text-muted-foreground` —— 绝不使用原始值如 `bg-blue-500`。

## 关键规则

这些规则是 **强制执行** 的。每个链接都指向包含“错误/正确”代码示例的文件。

### 样式与 Tailwind → [styling.md](./rules/styling.md)

- **`className` 用于布局而非样式。** 绝不覆盖组件的颜色或字体。
- **禁止使用 `space-x-*` 或 `space-y-*`。** 使用 `flex` 搭配 `gap-*`。对于垂直堆叠，使用 `flex flex-col gap-*`。
- **当宽高相等时使用 `size-*`。** 使用 `size-10` 而非 `w-10 h-10`。
- **使用 `truncate` 简写。** 而非 `overflow-hidden text-ellipsis whitespace-nowrap`。
- **禁止手动使用 `dark:` 颜色覆盖。** 使用语义化 Token（`bg-background`, `text-muted-foreground`）。
- **使用 `cn()` 处理条件类名。** 不要手动编写模板字符串三元表达式。
- **禁止在覆盖层 (overlay) 组件上手动设置 `z-index`。** Dialog, Sheet, Popover 等组件会自行处理层级。

### 表单与输入框 → [forms.md](./rules/forms.md)

- **表单使用 `FieldGroup` + `Field`。** 绝不使用原始 `div` 配合 `space-y-*` 或 `grid gap-*` 进行表单布局。
- **`InputGroup` 使用 `InputGroupInput`/`InputGroupTextarea`。** 在 `InputGroup` 内部绝不使用原始 `Input`/`Textarea`。
- **输入框内的按钮使用 `InputGroup` + `InputGroupAddon`。**
- **选项集（2–7 个选项）使用 `ToggleGroup`。** 不要循环渲染带有手动激活状态的 `Button`。
- **使用 `FieldSet` + `FieldLegend` 对相关复选框/单选框进行分组。** 不要使用带有标题的 `div`。
- **字段验证使用 `data-invalid` + `aria-invalid`。** 在 `Field` 上使用 `data-invalid`，在控件上使用 `aria-invalid`。禁用状态同理：`Field` 使用 `data-disabled`，控件使用 `disabled`。

### 组件结构 → [composition.md](./rules/composition.md)

- **子项始终位于其分组 (Group) 内部。** `SelectItem` → `SelectGroup`。`DropdownMenuItem` → `DropdownMenuGroup`。`CommandItem` → `CommandGroup`。
- **自定义触发器使用 `asChild` (Radix) 或 `render` (Base)。** 通过 `npx shadcn@latest info` 检查 `base` 字段。 → [base-vs-radix.md](./rules/base-vs-radix.md)
- **Dialog, Sheet 和 Drawer 始终需要标题。** 出于无障碍考虑，必须包含 `DialogTitle`, `SheetTitle`, `DrawerTitle`。如果视觉上需要隐藏，请使用 `className="sr-only"`。
- **使用完整的 Card 组合。** `CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`。不要将所有内容塞进 `CardContent`。
- **Button 没有 `isPending`/`isLoading`。** 使用 `Spinner` + `data-icon` + `disabled` 进行组合。
- **`TabsTrigger` 必须位于 `TabsList` 内部。** 绝不直接在 `Tabs` 中渲染触发器。
- **`Avatar` 始终需要 `AvatarFallback`。** 以防图片加载失败。

### 使用组件而非自定义标记 → [composition.md](./rules/composition.md)

- **优先使用现有组件。** 在编写带有样式的 `div` 之前，先检查组件是否存在。
- **提示框使用 `Alert`。** 不要构建自定义样式的 div。
- **空状态使用 `Empty`。** 不要构建自定义空状态标记。
- **通过 `sonner` 发送 Toast。** 使用来自 `sonner` 的 `toast()`。
- **使用 `Separator`** 而非 `<hr>` 或 `<div className="border-t">`。
- **使用 `Skeleton`** 作为加载占位符。不要使用自定义的 `animate-pulse` div。
- **使用 `Badge`** 而非自定义样式的 span。

### 图标 → [icons.md](./rules/icons.md)

- **`Button` 中的图标使用 `data-icon`。** 在图标上使用 `data-icon="inline-start"` 或 `data-icon="inline-end"`。
- **禁止在组件内部的图标上使用尺寸类。** 组件通过 CSS 处理图标尺寸。禁止使用 `size-4` 或 `w-4 h-4`。
- **以对象形式传递图标，而非字符串键。** 使用 `icon={CheckIcon}`，而非字符串查找。

### CLI

- **禁止手动解码或获取预设代码。** 对于现有项目直接传递给 `npx shadcn@latest apply --preset <code>`，或在初始化时使用 `npx shadcn@latest init --preset <code>`。

## 关键模式

这些是正确 shadcn/ui 代码中最常见的差异化模式。对于特殊情况，请参阅上面链接的规则文件。

```tsx
// 表单布局：FieldGroup + Field，而非 div + Label。
<FieldGroup>
  <Field>
    <FieldLabel htmlFor="email">Email</FieldLabel>
    <Input id="email" />
  </Field>
</FieldGroup>

// 验证：Field 使用 data-invalid，控件使用 aria-invalid。
<Field data-invalid>
  <FieldLabel>Email</FieldLabel>
  <Input aria-invalid />
  <FieldDescription>无效的邮箱。</FieldDescription>
</Field>

// 按钮中的图标：使用 data-icon，无尺寸类。
<Button>
  <SearchIcon data-icon="inline-start" />
  搜索
</Button>

// 间距：使用 gap-*，而非 space-y-*。
<div className="flex flex-col gap-4">  // 正确
<div className="space-y-4">           // 错误

// 相等维度：使用 size-*，而非 w-* h-*。
<Avatar className="size-10">   // 正确
<Avatar className="w-10 h-10"> // 错误

// 状态颜色：使用 Badge 变体或语义化 Token，而非原始颜色。
<Badge variant="secondary">+20.1%</Badge>    // 正确
<span className="text-emerald-600">+20.1%</span> // 错误
```

## 组件选择

| 需求 | 使用 |
| -------------------------- | --------------------------------------------------------------------------------------------------- |
| 按钮/操作 | 带有适当变体的 `Button` |
| 表单输入 | `Input`, `Select`, `Combobox`, `Switch`, `Checkbox`, `RadioGroup`, `Textarea`, `InputOTP`, `Slider` |
| 2–5 个选项切换 | `ToggleGroup` + `ToggleGroupItem` |
| 数据显示 | `Table`, `Card`, `Badge`, `Avatar` |
| 导航 | `Sidebar`, `NavigationMenu`, `Breadcrumb`, `Tabs`, `Pagination` |
| 覆盖层 | `Dialog` (模态), `Sheet` (侧边栏), `Drawer` (底部抽屉), `AlertDialog` (确认框) |
| 反馈 | `sonner` (toast), `Alert`, `Progress`, `Skeleton`, `Spinner` |
| 命令面板 | `Dialog` 内部的 `Command` |
| 图表 | `Chart` (包装 Recharts) |
| 布局 | `Card`, `Separator`, `Resizable`, `ScrollArea`, `Accordion`, `Collapsible` |
| 空状态 | `Empty` |
| 菜单 | `DropdownMenu`, `ContextMenu`, `Menubar` |
| 提示/信息 | `Tooltip`, `HoverCard`, `Popover` |

## 关键字段

注入的项目上下文包含以下关键字段：

- **`aliases`** → 使用实际的导入别名前缀（如 `@/`, `~/`），绝不硬编码。
- **`isRSC`** → 当为 `true` 时，使用 `useState`, `useEffect`, 事件处理器或浏览器 API 的组件需要在文件顶部添加 `"use client"`。在建议指令时务必参考此字段。
- **`tailwindVersion`** → `"v4"` 使用 `@theme inline` 块； `"v3"` 使用 `tailwind.config.js`。
- **`tailwindCssFile`** → 定义自定义 CSS 变量的全局 CSS 文件。始终编辑此文件，绝不创建新文件。
- **`style`** → 组件视觉处理（如 `nova`, `vega`）。
- **`base`** → 基础库（`radix` 或 `base`）。影响组件 API 和可用 Props。
- **`iconLibrary`** → 决定图标导入。`lucide` 使用 `lucide-react`，`tabler` 使用 `@tabler/icons-react` 等。绝不假设是 `lucide-react`。
- **`resolvedPaths`** → 组件、工具类、Hooks 等的准确文件系统目标。
- **`framework`** → 路由和文件约定（如 Next.js App Router vs Vite SPA）。
- **`packageManager`** → 用于任何非 shadcn 的依赖安装（如 `pnpm add date-fns` vs `npm install date-fns`）。

完整字段参考见 [cli.md — `info` 命令](./cli.md)。

## 组件文档、示例与用法

运行 `npx shadcn@latest docs <component>` 获取组件的文档、示例和 API 参考 URL。获取这些 URL 以获取实际内容。

```bash
npx shadcn@latest docs button dialog select
```

**在创建、修复、调试或使用组件时，务必先运行 `npx shadcn@latest docs` 并获取 URL。** 这能确保你基于正确的 API 和用法模式工作，而非凭空猜测。

## 工作流

1. **获取项目上下文** —— 已在上方注入。如需刷新，请再次运行 `npx shadcn@latest info`。
2. **优先检查已安装组件** —— 在运行 `add` 之前，始终从项目上下文中检查 `components` 列表或列出 `resolvedPaths.ui` 目录。不要导入尚未添加的组件，也不要重复添加已安装的组件。
3. **查找组件** —— `npx shadcn@latest search`。
4. **获取文档与示例** —— 运行 `npx shadcn@latest docs <component>` 获取 URL 并提取内容。使用 `npx shadcn@latest view` 浏览尚未安装的注册表项。要预览已安装组件的更改，使用 `npx shadcn@latest add --diff`。
5. **安装或更新** —— `npx shadcn@latest add`。更新现有组件时，使用 `--dry-run` 和 `--diff` 预检更改（见下文 [更新组件](#更新组件)）。
6. **修复第三方组件的导入** —— 从社区注册表（如 `@bundui`, `@magicui`）添加组件后，检查新增的非 UI 文件中是否存在硬编码的导入路径（如 `@/components/ui/...`）。这些可能与项目实际别名不符。使用 `npx shadcn@latest info` 获取正确的 `ui` 别名（如 `@workspace/ui/components`）并重写导入。CLI 会重写其自身 UI 文件的导入，但第三方注册表组件可能使用不匹配的默认路径。
7. **检查新增组件** —— 从任何注册表添加组件或区块后，**务必阅读新增文件并验证其正确性**。检查是否缺少子组件（如只有 `SelectItem` 缺少 `SelectGroup`）、缺少导入、组合错误或违反了 [关键规则](#关键规则)。同时根据项目上下文中的 `iconLibrary` 替换图标导入。在继续之前修复所有问题。
8. **注册表必须明确** —— 当用户要求添加区块或组件时，**不要猜测注册表**。如果没有指定注册表（如用户说“添加登录区块”而未指明 `@shadcn`, `@tailark` 等），请询问使用哪个注册表。绝不代表用户默认选择注册表。
9. **切换预设** —— 先询问用户：**覆盖 (overwrite)**、**部分 (partial)**、**合并 (merge)** 还是 **跳过 (skip)**？
   - **覆盖**：`npx shadcn@latest apply --preset <code>`。覆盖检测到的组件、字体和 CSS 变量。
   - **部分**：`npx shadcn@latest apply --preset <code> --only theme,font`。仅更新选定的预设部分，不重新安装 UI 组件。支持的值为 `theme` 和 `font`；允许逗号分隔的组合。`icon` 故意不予支持，因为图标更改可能需要全组件重新安装和转换。
   - **合并**：执行 `npx shadcn@latest init --preset <code> --force --no-reinstall`，然后运行 `npx shadcn@latest info` 列出已安装组件，接着对每个已安装组件使用 `--dry-run` 和 `--diff` 进行[智能合并](#更新组件)。
   - **跳过**：`npx shadcn@latest init --preset <code> --force --no-reinstall`。仅更新配置和 CSS，保留组件不变。
   - **重要提示**：始终在用户项目目录内运行预设命令。`apply` 仅适用于已有 `components.json` 文件的现有项目。CLI 会自动保留 `components.json` 中的当前基础（`base` vs `radix`）。如果必须使用临时目录（如进行 `--dry-run` 对比），请显式传递 `--base <current-base>` —— 预设代码不包含基础库信息。

## 更新组件

当用户要求从上游更新组件并保留本地修改时，使用 `--dry-run` 和 `--diff` 进行智能合并。**绝不手动从 GitHub 获取原始文件 —— 始终使用 CLI。**

1. 运行 `npx shadcn@latest add <component> --dry-run` 查看受影响的文件。
2. 对每个文件，运行 `npx shadcn@latest add <component> --diff <file>` 查看上游与本地的差异。
3. 根据差异决定：
   - 无本地修改 → 可安全覆盖。
   - 有本地修改 → 阅读本地文件，分析差异，并在保留本地修改的同时应用上游更新。
   - 用户说“全部更新” → 使用 `--overwrite`，但需先确认。
4. **未经用户明确同意，绝不使用 `--overwrite`。**

## 快速参考

```bash
# 创建新项目
npx shadcn@latest init --name my-app --preset base-nova
npx shadcn@latest init --name my-app --preset a2r6bw --template vite

# 创建 Monorepo 项目
npx shadcn@latest init --name my-app --preset base-nova --monorepo
npx shadcn@latest init --name my-app --preset base-nova --template next --monorepo

# 初始化现有项目
npx shadcn@latest init --preset base-nova
npx shadcn@latest init --defaults  # 快捷方式：--template=next --preset=nova (隐含 base 样式)

# 对现有项目应用预设
npx shadcn@latest apply --preset a2r6bw
npx shadcn@latest apply a2r6bw
npx shadcn@latest apply --preset a2r6bw --only theme
npx shadcn@latest apply --preset a2r6bw --only font
npx shadcn@latest apply --preset a2r6bw --only theme,font

# 添加组件
npx shadcn@latest add button card dialog
npx shadcn@latest add @magicui/shimmer-button
npx shadcn@latest add --all

# 添加/更新前预览更改
npx shadcn@latest add button --dry-run
npx shadcn@latest add button --diff button.tsx
npx shadcn@latest add @acme/form --view button.tsx

# 搜索注册表
npx shadcn@latest search @shadcn -q "sidebar"
npx shadcn@latest search @tailark -q "stats"

# 获取组件文档和示例 URL
npx shadcn@latest docs button dialog select

# 查看注册表项详情（针对未安装项）
npx shadcn@latest view @shadcn/button
```

**命名预设 (Named presets)：** `nova`, `vega`, `maia`, `lyra`, `mira`, `luma`
**模板 (Templates)：** `next`, `vite`, `start`, `react-router`, `astro` (均支持 `--monorepo`) 以及 `laravel` (不支持 monorepo)
**预设代码 (Preset codes)：** 版本前缀的 base62 字符串 (如 `a2r6bw` 或 `b0`)，来自 [ui.shadcn.com](https://ui.shadcn.com)。

## 详细参考

- [rules/forms.md](./rules/forms.md) — FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, 验证状态
- [rules/composition.md](./rules/composition.md) — 分组, 覆盖层, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button 加载状态
- [rules/icons.md](./rules/icons.md) — data-icon, 图标尺寸, 以对象形式传递图标
- [rules/styling.md](./rules/styling.md) — 语义化颜色, 变体, className, 间距, 尺寸, truncate, 暗黑模式, cn(), z-index
- [rules/base-vs-radix.md](./rules/base-vs-radix.md) — asChild vs render, Select, ToggleGroup, Slider, Accordion
- [cli.md](./cli.md) — 命令, 标志, 预设, 模板
- [customization.md](./customization.md) — 主题化, CSS 变量, 扩展组件

