shadcn-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseshadcn/ui Best Practices
shadcn/ui 最佳实践
This skill covers best practices for working with shadcn/ui — component imports, className utilities, form building, theming, and data tables.
本技能涵盖使用shadcn/ui的最佳实践——组件导入、className工具类、表单构建、主题设置和数据表格相关内容。
Use-When
适用场景
This skill activates when:
- Agent works with shadcn/ui components
- Agent adds or imports shadcn components
- Agent builds forms with validation
- Agent configures theming or dark mode
- Agent creates data tables
当以下情况时激活本技能:
- Agent 处理 shadcn/ui 组件
- Agent 添加或导入 shadcn 组件
- Agent 构建带验证的表单
- Agent 配置主题或深色模式
- Agent 创建数据表格
Core Rules
核心规则
- ALWAYS import shadcn components from
@/components/ui/{component-name} - ALWAYS use the utility for className merging
cn() - ALWAYS use Zod + React Hook Form for form validation
- ALWAYS use CSS variables for theming (not hardcoded colors)
- ALWAYS use TanStack Table for data tables
- ALWAYS check components.json to identify the primitive library (Radix vs Base UI)
- ALWAYS use migration commands when upgrading between styles (,
migrate radix)migrate rtl
- 始终从 导入 shadcn 组件
@/components/ui/{component-name} - 始终使用 工具类合并 className
cn() - 始终使用 Zod + React Hook Form 进行表单验证
- 始终使用 CSS variables 进行主题设置(不要硬编码颜色)
- 始终使用 TanStack Table 构建数据表格
- 始终检查 components.json 以确定底层基础库(Radix vs Base UI)
- 升级样式时始终使用迁移命令(、
migrate radix)migrate rtl
Common Agent Mistakes
Agent 常见错误
- Using relative paths instead of alias paths
- Forgetting to import utility
cn() - Hardcoding colors instead of using CSS variables
- Building table logic manually instead of using TanStack Table
- Assuming all shadcn projects use Radix UI (Base UI is now available)
- Using Radix-specific imports in Base UI projects (or vice versa)
- 使用相对路径而非别名路径
- 忘记导入 工具类
cn() - 硬编码颜色而非使用 CSS variables
- 手动构建表格逻辑而非使用 TanStack Table
- 假设所有 shadcn 项目都使用 Radix UI(现在也支持 Base UI)
- 在 Base UI 项目中使用 Radix 专属导入(反之亦然)
Examples
示例
✅ Correct
✅ 正确
tsx
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"
function MyComponent({ className }) {
return (
<Button className={cn("base-class", className)}>
<Input placeholder="Enter email" />
</Button>
)
}tsx
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"
function MyComponent({ className }) {
return (
<Button className={cn("base-class", className)}>
<Input placeholder="Enter email" />
</Button>
)
}❌ Wrong
❌ 错误
tsx
// Using relative paths
import { Button } from "../../components/ui/button"
// Hardcoding colors
<Button className="bg-blue-500 text-white" />
// Building table manually
data.map(item => <tr><td>{item.name}</td></tr>)
// Assuming Radix - wrong for Base UI projects
import * as DialogPrimitive from "@radix-ui/react-dialog"tsx
// Using relative paths
import { Button } from "../../components/ui/button"
// Hardcoding colors
<Button className="bg-blue-500 text-white" />
// Building table manually
data.map(item => <tr><td>{item.name}</td></tr>)
// Assuming Radix - wrong for Base UI projects
import * as DialogPrimitive from "@radix-ui/react-dialog"Identifying Primitive Library
识别基础库
tsx
// Check components.json to determine which library the project uses
// Look for "style" field:
// - "base-*" styles use @base-ui/react
// - Other styles use @radix-ui/react-* or radix-ui
// Example: reading the config
// import fs from "fs"
// const config = JSON.parse(fs.readFileSync("components.json", "utf-8"))
// config.style === "base-vega" // true = Base UI, false = Radix
// The API is identical regardless of library
import { Dialog, DialogContent } from "@/components/ui/dialog"
// Works the same for both Radix and Base UI projectstsx
// Check components.json to determine which library the project uses
// Look for "style" field:
// - "base-*" styles use @base-ui/react
// - Other styles use @radix-ui/react-* or radix-ui
// Example: reading the config
// import fs from "fs"
// const config = JSON.parse(fs.readFileSync("components.json", "utf-8"))
// config.style === "base-vega" // true = Base UI, false = Radix
// The API is identical regardless of library
import { Dialog, DialogContent } from "@/components/ui/dialog"
// Works the same for both Radix and Base UI projects