🗂
初学者必見!shadcn/ui × React Hook Form × Zod で型安全な美しいフォームを作成!!!
💡 概要
本記事では、以下の技術スタックを用いて、美しくかつtypeScriptの型安全なフォームを構築する方法について紹介します。
- shadcn/ui
- react-hook-form
- zod
- TypeScript
- Next.js
- Reack
主に、フォームのバリデーション、UIの一貫性確保、保守性の高い実装を意識しました。
🧰 技術スタック
ライブラリ | 用途 |
---|---|
shadcn/ui |
コンポーネントUIライブラリ(Tailwindベース) |
react-hook-form |
フォームの状態管理 |
zod |
スキーマベースのバリデーション |
TypeScript |
静的型チェックと言語サポート |
🔧 セットアップ
shadcn/ui のインストール
npx shadcn-ui@latest init
フォーム用ライブラリの導入
npm install react-hook-form zod @hookform/resolvers
1. react-hook-form
- React でフォームを扱うためのライブラリ。
- 軽量・高速で、制御が明確。
- フォーム状態管理(値・エラー・バリデーション)を簡潔に扱える。
主な特徴
- フックベース:useForm, Controller, handleSubmit など
- パフォーマンス最適化済み(再レンダリングが最小限)
- シンプルなAPIで状態管理ができる
2. zod
- バリデーションと型定義を同時に行える スキーマベースのバリデーションライブラリ。
- Yup や Joi の代替として人気だが、Zodは TypeScriptとの親和性が圧倒的に高い。
例
const schema = z.object({
email: z.string().email(),
age: z.number().min(18),
});
- z.infer<typeof schema> を使えば、Zodのスキーマからそのまま型を生成できます!
3. @hookform/resolvers
-
react-hook-form と zod, yup, joi などの バリデーションライブラリを接続するための橋渡しライブラリ。
-
これがあることで、Zod で書いたスキーマを React Hook Form に統合できる。
例
import { zodResolver } from "@hookform/resolvers/zod";
const form = useForm<FormData>({
resolver: zodResolver(schema), // ← ZodとReact Hook Formを接続
});
shadcn/uiより必要なものをインストール
今回はInput,Button,Formを利用します。そのために以下でインストールします。
※本ページの説明はnpmを利用しています。
npx shadcn-ui@latest add input
npx shadcn-ui@latest add button
npx shadcn-ui@latest add form
今回はnameとemailだけですが、文章入力したい場合はtextareaをインストールしてください!
ユーザー登録フォーム
実際の実装例を紹介します!
// components/UserForm.tsx
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
// Zodスキーマ定義
const schema = z.object({
name: z.string().min(1, "名前は必須です"),
email: z.string().email("有効なメールアドレスを入力してください"),
});
type FormData = z.infer<typeof schema>;
export function UserForm() {
const form = useForm<FormData>({
resolver: zodResolver(schema),
defaultValues: { name: "", email: "" },
});
const onSubmit = (data: FormData) => {
console.log("送信データ:", data);
};
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>名前</FormLabel>
<FormControl>
<Input placeholder="山田 太郎" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>メールアドレス</FormLabel>
<FormControl>
<Input placeholder="example@mail.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">送信</Button>
</form>
</Form>
);
}
このコードはnameとemailのフォームを実装しています。
nameは1文字以上必須、emailはmail型でないと認識しません。
送信ボタンを押すことでコンソール上で入力したフォームのデータが表示されるようになります。
🧠 実装のポイント
zod による型定義はそのままフォームバリデーションに利用可能!
shadcn/ui は Tailwind を活用して、UIの一貫性と柔軟なカスタマイズが可能!
react-hook-form の useForm によりフォームステートの管理が簡単!
FormField や FormMessage などのラップコンポーネントで、コードの再利用性UI!
✅ まとめ
shadcn/ui × react-hook-form × zod の組み合わせにより、
UIとUXの両立
型安全なバリデーション
メンテナンスしやすいコード構造
を実現できます。プロジェクトの初期設計やチーム開発においてもおすすめのスタックです!
Discussion