67 - Shadcn/UI 组件库教程

适用人群:React/Next.js 开发者
难度:低-中
预计学习时间:5-10小时

什么是 Shadcn/UI?

不是传统组件库,而是可复制粘贴的组件集合。基于 Radix UI + Tailwind CSS,直接将组件源码复制到你的项目中,完全可控、可定制。

特点说明
不是npm包组件代码直接在你的项目中
完全可控可以随意修改任何组件
可访问基于 Radix UI,内置无障碍支持
美观默认设计精美,暗色模式支持
流行2024-2025最火的React组件方案

快速上手

# 创建Next.js项目
npx create-next-app@latest my-app --typescript --tailwind
cd my-app

# 初始化shadcn
npx shadcn@latest init

# 添加组件
npx shadcn@latest add button
npx shadcn@latest add card
npx shadcn@latest add input
npx shadcn@latest add dialog
npx shadcn@latest add table
npx shadcn@latest add form
npx shadcn@latest add toast
npx shadcn@latest add dropdown-menu
npx shadcn@latest add sheet
npx shadcn@latest add tabs


组件示例

// 使用 Button
import { Button } from '@/components/ui/button'

export function MyComponent() {
  return (
    <div className="flex gap-2">
      <Button>默认按钮</Button>
      <Button variant="secondary">次要按钮</Button>
      <Button variant="destructive">危险按钮</Button>
      <Button variant="outline">轮廓按钮</Button>
      <Button variant="ghost">幽灵按钮</Button>
      <Button variant="link">链接按钮</Button>
      <Button size="sm">小按钮</Button>
      <Button size="lg">大按钮</Button>
      <Button disabled>禁用</Button>
    </div>
  )
}

// Card组件
import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
  CardFooter
} from '@/components/ui/card'

export function PostCard() {
  return (
    <Card className="w-[350px]">
      <CardHeader>
        <CardTitle>文章标题</CardTitle>
        <CardDescription>文章描述...</CardDescription>
      </CardHeader>
      <CardContent>
        <p>文章内容...</p>
      </CardContent>
      <CardFooter className="flex justify-between">
        <Button variant="outline">取消</Button>
        <Button>确认</Button>
      </CardFooter>
    </Card>
  )
}

// Dialog弹窗
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger
} from '@/components/ui/dialog'

export function MyDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>打开弹窗</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>确认操作</DialogTitle>
          <DialogDescription>确定要执行此操作吗?</DialogDescription>
        </DialogHeader>
        <div className="flex justify-end gap-2">
          <Button variant="outline">取消</Button>
          <Button>确认</Button>
        </div>
      </DialogContent>
    </Dialog>
  )
}

// DataTable表格
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow
} from '@/components/ui/table'

export function DataTable() {
  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>姓名</TableHead>
          <TableHead>邮箱</TableHead>
          <TableHead>角色</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell>Alice</TableCell>
          <TableCell>alice@example.com</TableCell>
          <TableCell>管理员</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  )
}

// Form表单(配合react-hook-form + zod)
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import * as z from 'zod'
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
import { Input } from '@/components/ui/input'

const formSchema = z.object({
  username: z.string().min(2, '至少2个字符'),
  email: z.string().email('请输入有效邮箱'),
})

export function MyForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: { username: '', email: '' }
  })

  function onSubmit(values: z.infer<typeof formSchema>) {
    console.log(values)
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
        <FormField control={form.control} name="username" render={({ field }) => (
          <FormItem>
            <FormLabel>用户名</FormLabel>
            <FormControl><Input {...field} /></FormControl>
            <FormMessage />
          </FormItem>
        )} />
        <FormField control={form.control} name="email" render={({ field }) => (
          <FormItem>
            <FormLabel>邮箱</FormLabel>
            <FormControl><Input {...field} /></FormControl>
            <FormMessage />
          </FormItem>
        )} />
        <Button type="submit">提交</Button>
      </form>
    </Form>
  )
}


常用组件列表

组件命令用途
Buttonadd button按钮
Cardadd card卡片容器
Inputadd input输入框
Dialogadd dialog弹窗
Tableadd table表格
Formadd form表单
Toastadd toast消息提示
Tabsadd tabs标签页
Selectadd select下拉选择
Sheetadd sheet侧边栏弹窗
Dropdown Menuadd dropdown-menu下拉菜单
Commandadd command命令面板
Calendaradd calendar日历
Chartadd chart图表

推荐资源

资源说明
ui.shadcn.com官方文档和组件预览
shadcnui.aiAI生成组件
Taxonomy官方示例项目
Aceternity UIshadcn风格动画组件
返回首页