shadcn/uiとは
shadcn/uiは、Radix UIとTailwind CSSをベースにしたコンポーネントコレクションです。コンポーネントをコピー&ペーストして使用し、完全にカスタマイズ可能です。
2025年の主な更新
新しいCLI
# 初期化(より対話的に)
npx shadcn@latest init
# コンポーネント追加
npx shadcn@latest add button
npx shadcn@latest add card dialog
# 複数同時追加
npx shadcn@latest add button card dialog dropdown-menu
# 全コンポーネント追加
npx shadcn@latest add --all
新コンポーネント
Sidebar
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from "@/components/ui/sidebar";
export function AppSidebar() {
return (
<Sidebar>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Application</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<Home /> Dashboard
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
);
}
Chart(Recharts統合)
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { Bar, BarChart, XAxis, YAxis } from "recharts";
const chartData = [
{ month: "Jan", revenue: 186 },
{ month: "Feb", revenue: 305 },
{ month: "Mar", revenue: 237 },
];
export function RevenueChart() {
return (
<ChartContainer config={{ revenue: { label: "Revenue", color: "#2563eb" } }}>
<BarChart data={chartData}>
<XAxis dataKey="month" />
<YAxis />
<Bar dataKey="revenue" fill="var(--color-revenue)" />
<ChartTooltip content={<ChartTooltipContent />} />
</BarChart>
</ChartContainer>
);
}
Breadcrumb
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
export function BreadcrumbDemo() {
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/products">Products</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Current Page</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
);
}
テーマのカスタマイズ
/* globals.css */
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ... */
}
}
components.json
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
よく使うパターン
フォーム
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import * as 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),
});
export function LoginForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
});
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="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Login</Button>
</form>
</Form>
);
}
ダイアログ
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
export function SettingsDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Settings</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Settings</DialogTitle>
<DialogDescription>
Manage your account settings.
</DialogDescription>
</DialogHeader>
{/* コンテンツ */}
</DialogContent>
</Dialog>
);
}
Registry(コンポーネント共有)
チームやコミュニティでカスタムコンポーネントを共有できます。
// registry.json
{
"name": "my-component",
"type": "components:ui",
"files": ["my-component.tsx"],
"dependencies": ["@radix-ui/react-dialog"]
}
関連記事
- Reactチートシート - React基礎
- Tailwindチートシート - Tailwind CSS
- Next.jsチートシート - Next.js統合