今回やること
shadcn/uiは、完成品パッケージを読み込むのではなく、コンポーネントのコードを自分のプロジェクトへ追加して使うUI集です。
導入後のコンポーネントは自分たちのコードになります。見た目だけでなく、責任範囲とアクセシビリティを確認する必要があります。
この記事では次を学びます。
- shadcn/uiセットアップ
- コンポーネント追加
- テーマカスタマイズ
- フォーム構築
- ダークモード
Step 1: セットアップ
npx create-next-app@latest my-app --typescript --tailwind
cd my-app
npx shadcn-ui@latest init
初期設定で以下を選択:
- TypeScript: yes
- Style: Default
- Base color: Slate
- CSS variables: yes
Step 2: コンポーネント追加
# 個別追加
npx shadcn-ui@latest add button
npx shadcn-ui@latest add card
npx shadcn-ui@latest add input
npx shadcn-ui@latest add form
# 複数追加
npx shadcn-ui@latest add button card input dialog
Step 3: 基本的な使用
ポイント: shadcn/uiのコンポーネントはプロジェクト内にコピーされるため、自由にカスタマイズ可能です。npmパッケージとは異なり、完全な所有権を持てます。
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
export default function HomePage() {
return (
<div className="p-8">
<Card className="max-w-md">
<CardHeader>
<CardTitle>ログイン</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<Input placeholder="メールアドレス" />
<Input type="password" placeholder="パスワード" />
<Button className="w-full">ログイン</Button>
</CardContent>
</Card>
</div>
);
}
実践メモ: variantプロパティでボタンの見た目を簡単に切り替えられます。デザインシステムの一貫性を保つのに最適です。
Step 4: バリアント
<Button variant="default">Default</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
Step 5: フォーム構築
npx shadcn-ui@latest add form
npm install zod react-hook-form @hookform/resolvers
'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 schema = z.object({
email: z.string().email('有効なメールアドレスを入力'),
password: z.string().min(8, '8文字以上'),
});
export function LoginForm() {
const form = useForm({
resolver: zodResolver(schema),
defaultValues: { email: '', password: '' },
});
const onSubmit = (data: z.infer<typeof schema>) => {
console.log(data);
};
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>メール</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>パスワード</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full">ログイン</Button>
</form>
</Form>
);
}
Step 6: ダイアログ
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
export function ConfirmDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="destructive">削除</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>本当に削除しますか?</DialogTitle>
<DialogDescription>
この操作は取り消せません。
</DialogDescription>
</DialogHeader>
<div className="flex justify-end gap-2">
<Button variant="outline">キャンセル</Button>
<Button variant="destructive">削除</Button>
</div>
</DialogContent>
</Dialog>
);
}
注意: テーマのCSS変数を変更する際は、lightモードとdarkモードの両方を必ず更新してください。片方だけ変更すると、モード切替時に表示が崩れます。
Step 7: テーマカスタマイズ
/* globals.css */
@layer base {
:root {
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
/* カスタムカラー */
}
.dark {
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
}
}
導入後に整えること
shadcn/uiは、追加したコンポーネントのコードがプロジェクト内に入ります。そのため、導入して終わりではなく、自分たちのUI規約に合わせて調整し、再利用しやすい形に整えることが重要です。
特にフォーム、ダイアログ、ドロップダウンはアクセシビリティに関わるため、見た目だけで判断しないようにします。キーボード操作、フォーカス移動、エラー表示まで確認すると、実用的なUIになります。
カスタマイズの基準
- 色や余白はデザイントークンに寄せる
- コンポーネントを直接改変する前に用途を確認する
- 同じパターンを何度も書かないようにラップする
- 追加したコードの責任範囲をチームで共有する
動作確認
コンポーネントを追加したら、次を確認します。
| 確認項目 | OKの状態 |
|---|---|
| 表示 | light/darkの両方で崩れない |
| キーボード操作 | Tab、Enter、Escで操作できる |
| フォーカス | 現在位置が視覚的に分かる |
| エラー表示 | Formのエラーが入力欄と対応している |
| 再利用 | 同じUIを何度もコピペしていない |
DialogやDropdownは、閉じる操作、フォーカス移動、読み上げ名を必ず確認します。
練習
次のログインフォームを作ってください。
ButtonとInputを追加するCardの中にフォームを配置する- Zodでメールアドレスとパスワードを検証する
- 送信失敗時のエラー表示を出す
- darkモードでも読めるか確認する
次のステップ
フォーム検証は Zodバリデーション入門 と組み合わせると実装しやすくなります。Tailwindの基礎は Tailwind CSS実践ガイド と Tailwindチートシート を確認してください。
まとめ
shadcn/uiはコピー&ペースト型のUIライブラリで、完全なカスタマイズ性を持ちます。Radix UIとTailwind CSSをベースにしています。