shadcn/ui Expert
Comprehensive guide for building production UIs with shadcn/ui, Tailwind CSS, react-hook-form, and zod.
Core Concepts
shadcn/ui is not a component library — it's a collection of copy-paste components built on Radix UI primitives. You own the code. Components are added to your project, not installed as dependencies.
Installation
CODEBLOCK0
Component Categories & When to Use
Layout & Navigation
| Component | Use When |
|---|
| INLINECODE0 | App-level navigation with collapsible sections |
| INLINECODE1 |
Top-level site navigation with dropdowns |
|
breadcrumb | Showing page hierarchy/location |
|
tabs | Switching between related views in same context |
|
separator | Visual divider between content sections |
|
sheet | Slide-out panel (mobile nav, filters, detail views) |
|
resizable | Adjustable panel layouts |
Forms & Input
| Component | Use When |
|---|
| INLINECODE7 | Any form with validation (wraps react-hook-form) |
| INLINECODE8 |
Text, email, password, number inputs |
|
textarea | Multi-line text input |
|
select | Choosing from a list (native-like) |
|
combobox | Searchable select (uses
command +
popover) |
|
checkbox | Boolean or multi-select toggles |
|
radio-group | Single selection from small set |
|
switch | On/off toggle (settings, preferences) |
|
slider | Numeric range selection |
|
date-picker | Date selection (uses
calendar +
popover) |
|
toggle | Pressed/unpressed state (toolbar buttons) |
Feedback & Overlay
| Component | Use When |
|---|
| INLINECODE22 | Modal confirmation, forms, or detail views |
| INLINECODE23 |
Destructive action confirmation ("Are you sure?") |
|
sheet | Side panel for forms, filters, mobile nav |
|
toast | Brief non-blocking notifications (via
sonner) |
|
alert | Inline status messages (info, warning, error) |
|
tooltip | Hover hints for icons/buttons |
|
popover | Rich content on click (color pickers, date pickers) |
|
hover-card | Preview content on hover (user profiles, links) |
|
skeleton | Loading placeholders |
|
progress | Task completion indicators |
Data Display
| Component | Use When |
|---|
| INLINECODE33 | Tabular data display |
| INLINECODE34 |
Tables with sorting, filtering, pagination (uses
@tanstack/react-table) |
|
card | Content containers with header, body, footer |
|
badge | Status labels, tags, counts |
|
avatar | User profile images |
|
accordion | Collapsible FAQ or settings sections |
|
carousel | Image/content slideshows |
|
scroll-area | Custom scrollable containers |
Actions
| Component | Use When |
|---|
| INLINECODE42 | Primary actions, form submissions |
| INLINECODE43 |
Context menus, action menus |
|
context-menu | Right-click menus |
|
menubar | Application menu bars |
|
command | Command palette / search (⌘K) |
Form Patterns (react-hook-form + zod)
Complete Form Example
CODEBLOCK1
CODEBLOCK2
Form with Server Action
CODEBLOCK3
Theming & Dark Mode
Setup with next-themes
CODEBLOCK4
CODEBLOCK5
CODEBLOCK6
Custom Colors in globals.css
CODEBLOCK7
Common Layouts
App Shell with Sidebar
CODEBLOCK8
Responsive Header with Mobile Nav
CODEBLOCK9
Card Grid
CODEBLOCK10
Tailwind CSS Patterns
Common Utility Patterns
CODEBLOCK11
Button Variants
CODEBLOCK12
Toast Notifications
CODEBLOCK13
CODEBLOCK14
Command Palette (⌘K)
CODEBLOCK15
shadcn/ui 专家
使用 shadcn/ui、Tailwind CSS、react-hook-form 和 zod 构建生产级 UI 的全面指南。
核心概念
shadcn/ui 不是一个组件库——它是基于 Radix UI 原语构建的可复制粘贴组件集合。你拥有代码的所有权。组件是添加到你的项目中,而不是作为依赖项安装。
安装
bash
在 Next.js 项目中初始化 shadcn/ui
npx shadcn@latest init
添加单个组件
npx shadcn@latest add button
npx shadcn@latest add card
npx shadcn@latest add dialog
npx shadcn@latest add form
npx shadcn@latest add input
npx shadcn@latest add select
npx shadcn@latest add table
npx shadcn@latest add toast
npx shadcn@latest add dropdown-menu
npx shadcn@latest add sheet
npx shadcn@latest add tabs
npx shadcn@latest add sidebar
一次性添加多个组件
npx shadcn@latest add button card input label textarea select checkbox
组件分类及使用场景
布局与导航
| 组件 | 使用场景 |
|---|
| sidebar | 带有可折叠部分的应用程序级导航 |
| navigation-menu |
带有下拉菜单的顶级网站导航 |
| breadcrumb | 显示页面层级/位置 |
| tabs | 在同一上下文中切换相关视图 |
| separator | 内容区域之间的视觉分隔线 |
| sheet | 滑出面板(移动端导航、筛选器、详情视图) |
| resizable | 可调整大小的面板布局 |
表单与输入
| 组件 | 使用场景 |
|---|
| form | 任何需要验证的表单(包装 react-hook-form) |
| input |
文本、邮箱、密码、数字输入 |
| textarea | 多行文本输入 |
| select | 从列表中选择(类似原生) |
| combobox | 可搜索的选择框(使用 command + popover) |
| checkbox | 布尔或多选开关 |
| radio-group | 从小集合中单选 |
| switch | 开/关切换(设置、偏好) |
| slider | 数值范围选择 |
| date-picker | 日期选择(使用 calendar + popover) |
| toggle | 按下/未按下状态(工具栏按钮) |
反馈与覆盖层
| 组件 | 使用场景 |
|---|
| dialog | 模态确认、表单或详情视图 |
| alert-dialog |
破坏性操作确认(你确定吗?) |
| sheet | 表单、筛选器、移动端导航的侧面板 |
| toast | 简短的非阻塞通知(通过 sonner) |
| alert | 内联状态消息(信息、警告、错误) |
| tooltip | 图标/按钮的悬停提示 |
| popover | 点击时显示丰富内容(颜色选择器、日期选择器) |
| hover-card | 悬停时预览内容(用户资料、链接) |
| skeleton | 加载占位符 |
| progress | 任务完成指示器 |
数据展示
| 组件 | 使用场景 |
|---|
| table | 表格数据展示 |
| data-table |
支持排序、筛选、分页的表格(使用 @tanstack/react-table) |
| card | 带有头部、主体、底部的内容容器 |
| badge | 状态标签、标签、计数 |
| avatar | 用户头像 |
| accordion | 可折叠的常见问题或设置区域 |
| carousel | 图片/内容轮播 |
| scroll-area | 自定义可滚动容器 |
操作
| 组件 | 使用场景 |
|---|
| button | 主要操作、表单提交 |
| dropdown-menu |
上下文菜单、操作菜单 |
| context-menu | 右键菜单 |
| menubar | 应用程序菜单栏 |
| command | 命令面板/搜索(⌘K) |
表单模式(react-hook-form + zod)
完整表单示例
bash
npx shadcn@latest add form input select textarea checkbox button
tsx
use client
import { zodResolver } from @hookform/resolvers/zod
import { useForm } from react-hook-form
import { z } from zod
import { Button } from @/components/ui/button
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from @/components/ui/form
import { Input } from @/components/ui/input
import { Textarea } from @/components/ui/textarea
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from @/components/ui/select
import { Checkbox } from @/components/ui/checkbox
import { toast } from sonner
const formSchema = z.object({
name: z.string().min(2, 姓名至少需要2个字符),
email: z.string().email(邮箱地址无效),
role: z.enum([admin, user, editor], { required_error: 请选择一个角色 }),
bio: z.string().max(500).optional(),
notifications: z.boolean().default(false),
})
type FormValues = z.infer
export function UserForm() {
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
name: ,
email: ,
bio: ,
notifications: false,
},
})
async function onSubmit(values: FormValues) {
try {
await createUser(values)
toast.success(用户创建成功)
form.reset()
} catch (error) {
toast.error(创建用户失败)
}
}
return (
)
}
使用服务器操作