shadcn/ui with Claude Code
Learn about shadcn/ui using Claude Code. Practical tips and code examples included.
shadcn/uiでプロダクション品質のUIを構築する
shadcn/uiは、Radix UIとTailwind CSSをベースにしたコンポーネントコレクションです。npm パッケージではなく、コードを直接プロジェクトにコピーして使う設計のため、自由にカスタマイズできます。Claude Codeはコンポーネントの導入からカスタマイズまで強力にサポートします。
初期セットアップ
Claude Codeにプロジェクトへの導入を依頼しましょう。
> Next.jsプロジェクトにshadcn/uiをセットアップして。
> ダークモード対応、日本語フォント設定も含めて。
// tailwind.config.ts
import type { Config } from "tailwindcss";
const config: Config = {
darkMode: ["class"],
content: [
"./src/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
],
theme: {
extend: {
fontFamily: {
sans: [
"Noto Sans JP",
"Inter",
"system-ui",
"sans-serif",
],
},
colors: {
border: "hsl(var(--border))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
},
},
};
export default config;
データテーブルの構築
shadcn/uiのDataTableコンポーネントをカスタマイズする例です。
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
interface DataTableProps<T> {
data: T[];
columns: ColumnDef<T>[];
searchPlaceholder?: string;
onRowClick?: (row: T) => void;
}
function DataTable<T extends { id: string }>({
data,
columns,
searchPlaceholder = "検索...",
onRowClick,
}: DataTableProps<T>) {
const [search, setSearch] = useState("");
const [sorting, setSorting] = useState<SortingState>([]);
const table = useReactTable({
data,
columns,
state: { sorting, globalFilter: search },
onSortingChange: setSorting,
onGlobalFilterChange: setSearch,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});
return (
<div>
<div className="flex items-center py-4">
<Input
placeholder={searchPlaceholder}
value={search}
onChange={(e) => setSearch(e.target.value)}
className="max-w-sm"
/>
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<TableHead key={header.id}>
{flexRender(header.column.columnDef.header, header.getContext())}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
onClick={() => onRowClick?.(row.original)}
className={onRowClick ? "cursor-pointer" : ""}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
前へ
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
次へ
</Button>
</div>
</div>
);
}
フォーム統合
shadcn/uiのFormコンポーネントとReact Hook Form + Zodの統合です。
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
const profileSchema = z.object({
displayName: z.string().min(2, "2文字以上入力してください"),
email: z.string().email("有効なメールアドレスを入力してください"),
role: z.enum(["developer", "designer", "manager"]),
bio: z.string().max(200).optional(),
});
function ProfileForm() {
const form = useForm<z.infer<typeof profileSchema>>({
resolver: zodResolver(profileSchema),
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
control={form.control}
name="displayName"
render={({ field }) => (
<FormItem>
<FormLabel>表示名</FormLabel>
<FormControl>
<Input placeholder="表示名を入力" {...field} />
</FormControl>
<FormDescription>公開プロフィールに表示される名前です。</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="role"
render={({ field }) => (
<FormItem>
<FormLabel>役職</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="役職を選択" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="developer">開発者</SelectItem>
<SelectItem value="designer">デザイナー</SelectItem>
<SelectItem value="manager">マネージャー</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">保存</Button>
</form>
</Form>
);
}
カスタムテーマの設計
プロジェクト固有のカラースキームを設定するパターンです。
/* globals.css */
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222 47% 11%;
--primary: 221 83% 53%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96%;
--secondary-foreground: 222 47% 11%;
--muted: 210 40% 96%;
--muted-foreground: 215 16% 47%;
--accent: 210 40% 96%;
--accent-foreground: 222 47% 11%;
--destructive: 0 84% 60%;
--destructive-foreground: 210 40% 98%;
--border: 214 32% 91%;
--radius: 0.5rem;
}
.dark {
--background: 222 47% 11%;
--foreground: 210 40% 98%;
--primary: 217 91% 60%;
--primary-foreground: 222 47% 11%;
--secondary: 217 33% 17%;
--secondary-foreground: 210 40% 98%;
--muted: 217 33% 17%;
--muted-foreground: 215 20% 65%;
--accent: 217 33% 17%;
--accent-foreground: 210 40% 98%;
--destructive: 0 63% 31%;
--destructive-foreground: 210 40% 98%;
--border: 217 33% 17%;
}
}
Zusammenfassung
shadcn/uiはコードをプロジェクトに直接取り込む設計のため、制約なく自由にカスタマイズできます。Claude Codeを活用すれば、コンポーネントの追加からテーマ設計、フォーム統合まで効率的に実装可能です。
Radix UIの基礎はRadix UIコンポーネント活用を、フォーム実装の詳細はReact Hook Form完全攻略を参照してください。shadcn/ui公式サイトも確認しておきましょう。
Related Posts
So beschleunigen Sie Ihre Nebenprojekte mit Claude Code [Mit Beispielen]
Erfahren Sie, wie Sie persönliche Entwicklungsprojekte mit Claude Code drastisch beschleunigen. Inklusive realer Beispiele und eines praktischen Workflows von der Idee bis zum Deployment.
So automatisieren Sie Refactoring mit Claude Code
Erfahren Sie, wie Sie Code-Refactoring mit Claude Code effizient automatisieren. Inklusive praktischer Prompts und konkreter Refactoring-Muster für reale Projekte.
Vollständiger CORS-Konfigurationsleitfaden mit Claude Code
Erfahren Sie alles über die CORS-Konfiguration mit Claude Code. Mit praktischen Tipps und Codebeispielen.