shadcn/ui 2025年の進化と新コンポーネント

10分 で読める | 2025.01.10

公式ドキュメント

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

新コンポーネント

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>
 );
}

ポイント: 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>
 );
}
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%;
 /* ... */
 }
}

実践メモ: CSS変数を活用することで、ダークモード対応やブランドカラーの切り替えが容易になります。

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"]
}

注意: shadcn/uiはコンポーネントライブラリではなくコードコレクションのため、バージョンアップの概念がありません。最新のコンポーネントを使う場合はCLIで再追加が必要です

まとめ

このニュースは、今すぐ全員が対応すべき話か、学習や新規開発で前提を更新しておく話かを分けて読むことが重要です。まずは公式情報で対象バージョンと影響範囲を確認し、自分の環境に関係する部分から見直してください。

関連記事

shadcn/uiを見るときの視点

shadcn/uiは、インストールして使うだけのコンポーネントライブラリではなく、コードを自分のプロジェクトに取り込んで育てる方式です。そのため、自由度が高い一方で、取り込んだ後の保守責任はプロジェクト側にあります。

デザインシステムが固まっているチームでは、トークン、余白、角丸、アクセシビリティ方針と合わせて調整すると効果的です。逆に、何も決めずにコンポーネントを増やすと、見た目は整っていても一貫性が崩れます。

採用時の確認

  • 取り込んだコンポーネントを自分たちで保守できるか
  • フォーム、モーダル、メニューのアクセシビリティを確認しているか
  • Tailwind設定とデザイントークンが整理されているか
  • コンポーネントを増やす基準があるか

参考リソース

← 一覧に戻る
PR
PR
PR
PR