shadcn-ui

shadcn-ui

熱門

提供完整的 shadcn/ui 元件庫模式,包含安裝、設定及實作無障礙 React 元件。適用於設定 shadcn/ui、安裝元件、使用 React Hook Form 和 Zod 建立表單、透過 Tailwind CSS 自訂主題,或實作按鈕、對話框、下拉選單、表格及複雜表單佈局等 UI 模式。

311星標
36分支
更新於 2026/6/22
SKILL.md
唯讀
名稱
shadcn-ui
描述

提供完整的 shadcn/ui 元件庫模式,包含安裝、設定及實作無障礙 React 元件。適用於設定 shadcn/ui、安裝元件、使用 React Hook Form 和 Zod 建立表單、透過 Tailwind CSS 自訂主題,或實作按鈕、對話框、下拉選單、表格及複雜表單佈局等 UI 模式。

shadcn/ui 元件模式

使用 shadcn/ui、Radix UI 和 Tailwind CSS 建立可存取、可自訂的 UI 元件。

概覽

  • 元件會複製到你的專案中 — 你擁有並可自訂程式碼
  • 基於 Radix UI 基礎元件,確保完整無障礙
  • 使用 Tailwind CSS 和 CSS 變數進行主題樣式設定
  • CLI 安裝方式:npx shadcn@latest add <component>

使用時機

當使用者要求涉及以下內容時啟用:

  • 「設定 shadcn/ui」、「初始化 shadcn」、「加入 shadcn 元件」
  • 「安裝 button/input/form/dialog/card/select/toast/table/chart」
  • 「React Hook Form」、「Zod 驗證」、「含驗證的表單」
  • 「無障礙元件」、「Radix UI」、「Tailwind 主題」
  • 「shadcn button」、「shadcn dialog」、「shadcn sheet」、「shadcn table」
  • 「深色模式」、「CSS 變數」、「自訂主題」
  • 「使用 Recharts 的圖表」、「長條圖」、「折線圖」、「圓餅圖」

快速參考

可用元件

元件 安裝指令 說明
button npx shadcn@latest add button 變體:default、destructive、outline、secondary、ghost、link
input npx shadcn@latest add input 文字輸入欄位
form npx shadcn@latest add form 整合 React Hook Form 與驗證
card npx shadcn@latest add card 包含標頭、內容、頁尾的容器
dialog npx shadcn@latest add dialog 模態覆蓋層
sheet npx shadcn@latest add sheet 滑出面板(上/右/下/左)
select npx shadcn@latest add select 下拉選單
toast npx shadcn@latest add toast 通知提示
table npx shadcn@latest add table 資料表格
menubar npx shadcn@latest add menubar 桌面風格的選單列
chart npx shadcn@latest add chart 包含主題的 Recharts 包裝
textarea npx shadcn@latest add textarea 多行文字輸入
checkbox npx shadcn@latest add checkbox 核取方塊
label npx shadcn@latest add label 無障礙表單標籤

操作說明

初始化專案

# 新的 Next.js 專案
npx create-next-app@latest my-app --typescript --tailwind --eslint --app
cd my-app
npx shadcn@latest init

# 現有專案
npm install tailwindcss-animate class-variance-authority clsx tailwind-merge lucide-react
npx shadcn@latest init

# 安裝元件
npx shadcn@latest add button input form card dialog select toast

基本元件用法

// 含變體與尺寸的按鈕
import { Button } from "@/components/ui/button"

<Button variant="default">預設</Button>
<Button variant="destructive" size="sm">刪除</Button>
<Button variant="outline" disabled>載入中...</Button>

含 Zod 驗證的表單

"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, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"

const formSchema = z.object({
  email: z.string().email("無效的電子郵件"),
  password: z.string().min(8, "密碼至少需要 8 個字元"),
})

export function LoginForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: { email: "", password: "" },
  })

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(console.log)} className="space-y-4">
        <FormField name="email" control={form.control} render={({ field }) => (
          <FormItem>
            <FormLabel>電子郵件</FormLabel>
            <FormControl><Input type="email" {...field} /></FormControl>
            <FormMessage />
          </FormItem>
        )} />
        <FormField name="password" control={form.control} render={({ field }) => (
          <FormItem>
            <FormLabel>密碼</FormLabel>
            <FormControl><Input type="password" {...field} /></FormControl>
            <FormMessage />
          </FormItem>
        )} />
        <Button type="submit">登入</Button>
      </form>
    </Form>
  )
}

更多進階多欄位表單、含 API 提交的聯絡表單及登入卡片模式,請參閱 references/forms-and-validation.md

對話框(模態)

import { Button } from "@/components/ui/button"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"

<Dialog>
  <DialogTrigger asChild>
    <Button variant="outline">開啟</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>編輯個人資料</DialogTitle>
    </DialogHeader>
    {/* 內容 */}
  </DialogContent>
</Dialog>

通知提示

// 1. 在 app/layout.tsx 中加入 <Toaster />
import { Toaster } from "@/components/ui/toaster"

// 2. 在元件中使用
import { useToast } from "@/components/ui/use-toast"

const { toast } = useToast()
toast({ title: "成功", description: "變更已儲存。" })
toast({ variant: "destructive", title: "錯誤", description: "發生錯誤。" })

長條圖

import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"
import { ChartContainer, ChartTooltipContent } from "@/components/ui/chart"

const chartConfig = {
  desktop: { label: "桌上型", color: "var(--chart-1)" },
} satisfies import("@/components/ui/chart").ChartConfig

<ChartContainer config={chartConfig} className="min-h-[200px] w-full">
  <BarChart data={data}>
    <CartesianGrid vertical={false} />
    <XAxis dataKey="month" />
    <Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
    <ChartTooltip content={<ChartTooltipContent />} />
  </BarChart>
</ChartContainer>

更多折線圖、區域圖和圓餅圖範例,請參閱 references/charts-components.md

範例

含驗證的登入表單

"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, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"

const formSchema = z.object({
  email: z.string().email("無效的電子郵件"),
  password: z.string().min(8, "至少 8 個字元"),
})

export function LoginForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: { email: "", password: "" },
  })

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(console.log)} className="space-y-4">
        <FormField name="email" control={form.control} render={({ field }) => (
          <FormItem>
            <FormLabel>電子郵件</FormLabel>
            <FormControl><Input type="email" {...field} /></FormControl>
            <FormMessage />
          </FormItem>
        )} />
        <FormField name="password" control={form.control} render={({ field }) => (
          <FormItem>
            <FormLabel>密碼</FormLabel>
            <FormControl><Input type="password" {...field} /></FormControl>
            <FormMessage />
          </FormItem>
        )} />
        <Button type="submit">登入</Button>
      </form>
    </Form>
  )
}

含操作的資料表格

import { ColumnDef } from "@tanstack/react-table"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { DataTable } from "@/components/ui/data-table"

const columns: ColumnDef<User>[] = [
  { id: "select", header: ({ table }) => (
    <Checkbox checked={table.getIsAllPageRowsSelected()} />
  ), cell: ({ row }) => (
    <Checkbox checked={row.getIsSelected()} />
  )},
  { accessorKey: "name", header: "姓名" },
  { accessorKey: "email", header: "電子郵件" },
  { id: "actions", cell: ({ row }) => (
    <Button variant="ghost" size="sm">編輯</Button>
  )},
]

含表單的對話框

import { Button } from "@/components/ui/button"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"

<Dialog>
  <DialogTrigger asChild>
    <Button variant="outline">新增使用者</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>新增使用者</DialogTitle>
    </DialogHeader>
    {/* <LoginForm /> */}
  </DialogContent>
</Dialog>

通知提示

import { useToast } from "@/components/ui/use-toast"
import { Button } from "@/components/ui/button"

const { toast } = useToast()

toast({ title: "已儲存", description: "變更已成功儲存。" })
toast({ variant: "destructive", title: "錯誤", description: "儲存失敗。" })

最佳實務

  • 無障礙:使用 Radix UI 基礎元件 — 內建 ARIA 屬性
  • 客戶端元件:為互動式元件(hooks、事件)加上 "use client"
  • 型別安全:使用 TypeScript 和 Zod 架構進行表單驗證
  • 主題設定:在 globals.css 中設定 CSS 變數以維持一致的設計
  • 自訂化:直接修改元件檔案 — 你擁有程式碼
  • 路徑別名:確保在 tsconfig.json 中設定 @ 別名
  • 註冊表安全性:僅從信任的註冊表安裝元件;在正式環境使用前審查產生的程式碼
  • 深色模式:使用 CSS 變數策略和 next-themes 設定
  • 表單:務必一起使用 FormFormFieldFormItemFormLabelFormMessage
  • Toaster:在根佈局中加入一次 <Toaster />

限制與警告

  • 非 NPM 套件:元件會複製到你的專案中,並非版本化的依賴項
  • 註冊表安全性:從 npx shadcn@latest add 取得的元件是遠端擷取;安裝前務必確認註冊表來源可信
  • 客戶端元件:大多數互動式元件需要 "use client" 指令
  • Radix 依賴:確保所有 @radix-ui 套件已安裝
  • 需要 Tailwind:元件依賴 Tailwind CSS 工具類別
  • 路徑別名:在 tsconfig.json 中設定 @ 別名以用於匯入

參考資料

詳細模式與程式碼範例請參閱以下檔案: