React Hook Formで実現する“やさしい”バリデーション設計
はじめに
どんなに正確なフォームでも、入力中に頻繁に赤字エラーが出たり、送信ボタンが押せなかったりすると、ユーザーは「自分が間違えているのか?」とストレスを感じてしまいます。
React Hook Form(以下、RHF)はバリデーションをシンプルに書ける便利なライブラリですが、「いつ」「どのように」チェックを走らせるかを意識すると、UXの質が大きく変わります。
今回は、**初学者でも実装できる“ユーザーフレンドリーなバリデーション設計”**をテーマに、
- ボタンの非活性での導線設計
- エラーメッセージの出し方とタイミング
-
isValid/isDirty/triggerなどの使い分け
を「理論+実装Tips」の形で解説します。
Step 1:RHFの基本的なバリデーションの流れをおさらい
まずは基本を確認しましょう。
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("email", { required: "メールアドレスは必須です" })} />
{errors.email && <p>{errors.email.message}</p>}
<button type="submit">送信</button>
</form>
);
React Hook Formの基本的な使い方についてこちらの記事で詳しく解説しています。
useFormとregister、handleSubmitやフォームのデータ操作について知りたい方はぜひご覧ください。
Step 2:ボタンの非活性で“押せない安心感”を作る
なぜ非活性にするのか
UXの観点では、「エラーを出す前にエラーを防ぐ」ことが理想です。
まだ入力が不完全な段階で送信できてしまうと、
- ページがガタッと動く
- 赤字が一斉に出る
- 「また間違えた」と思わせてしまう
といったストレス体験につながります。
そのため、「まだ条件を満たしていないならボタンを押せない状態にしておく」ことで、ユーザーに“安心感”を与える設計が有効です。
よく使われる3条件
| 条件名 | 意味 | 主な使いどころ |
|---|---|---|
isValid |
全てのバリデーションを通過したか | 正しい入力ができた時のみ活性化 |
isDirty |
1つでも入力が変更されたか | 初期状態で送信できないように |
isSubmitting |
送信中か | 二重送信を防止 |
実装例
const {
register,
handleSubmit,
formState: { isValid, isDirty, isSubmitting },
} = useForm({ mode: "onChange" });
// 送信前にバリデーションを発火させたいので、useFormのmode設定を行う
<button type="submit" disabled={!isDirty || !isValid || isSubmitting}>
{isSubmitting ? "送信中..." : "送信"}
</button>
Tips:UX視点の賛否
非活性にすることは効果的な場面がある反面、欠点も存在するので注意です。
- 利点:「そもそも押せない」ほうがミスを未然に防げる
- 欠点:「ボタンが押せない理由がわからず混乱する」リスク。項目数が多かったり、必須入力欄なのかどうか分かりにくい場合など。
Step 3:エラー表示を“気持ちよく”出すタイミングを考える
入力中に即座に赤文字エラーが出るフォーム、見たことありますよね?
あれは正確ではあっても、心理的には「怒られている感」が強いです。
ここでは**「いつチェックを走らせるか」**を設計することで、体験をやさしくできます。
| mode | チェックタイミング | ユーザー体験の印象 |
|---|---|---|
onSubmit |
送信時のみ | 最もシンプル、だが気づくのが遅い |
onBlur |
フォーカスを外した時 | 自然で丁寧、初心者におすすめ |
onChange |
入力のたび | リアルタイムで正確、だが忙しい印象 |
onTouched |
一度触れた後に随時 |
onBlurとonChangeの中間的 |
const { register } = useForm({
mode: "onBlur", // または "onChange"
});
Tips:UX視点の賛否
-
onChange派:「即時にフィードバックできる」 -
onBlur派:「入力中は集中でき、完了後にだけエラーを見る」
フォームが多項目ならonBlur、1〜2項目ならonChangeが無難だと思います。
Step 4:必要なときだけチェックを走らせる(triggerの使いどころ)
たとえば「メールアドレスを入力 → 認証コードを送信」するようなケースでは、
フォーム全体の送信前に 特定の項目だけ チェックしたいことがあります。
const { register, trigger, getValues } = useForm();
const handleSendCode = async () => {
const isValid = await trigger("email"); // emailだけチェック
if (isValid) {
sendCode(getValues("email"));
}
};
Tips:UX視点の賛否
mode指定で対応しきれない場面や、自分でタイミングを決めたい時にはtriggerが役に立ちますが、むやみに入れるのは避けたほうがよさそうです。
- 賛成派:「ユーザーが次のアクションをすぐ取れる」
- 懸念派:「バリデーションの一貫性が崩れる」
複数ステップフォームや途中送信ボタンを設ける場合に適しています。
Step 5:全体設計のまとめ ― “導くフォーム”を作る
ここまで紹介したテクニックを、UX観点で整理すると以下のようになります。
| 要素 | 技術 | UX上の目的 |
|---|---|---|
| ボタン非活性 |
isDirty, isValid, isSubmitting
|
エラーを未然に防ぐ |
| エラー表示 |
errors+メッセージ |
何が問題かを明確に伝える |
| チェックタイミング |
mode+trigger
|
適切な瞬間にやさしく知らせる |
これらを組み合わせると、「エラーで止めるフォーム」ではなく、
“ユーザーを導くフォーム” に進化します。
設計の指針
- 何を防ぎたいのか(誤送信?入力ミス?)
- いつ知らせたいのか(入力中?完了後?)
- どう感じさせたいのか(安心?即時性?)
たとえば「誤送信を防ぎたい」なら、isValid+isSubmittingでボタン制御。
「入力途中のストレスを減らしたい」なら、mode: "onBlur"でエラーを出すタイミングを遅らせる、など。
技術的な設定値の裏には、必ずUX上の「意図」があります。
RHFはその意図をコードで表現できる強力なツールです。
まとめ
- React Hook Formはバリデーションを簡単にするだけでなく、体験設計をコントロールするツール。
-
isValidやisSubmittingを組み合わせて「押せない安心感」を作る。 -
onBlurやtriggerで、ユーザーが“ちょうどいいタイミング”で気づける設計にする。 - 「エラーを出す」ではなく、「正しい入力に導く」発想で考える。
入力がスムーズで、エラーが自然に導かれるフォームは、
使う人の心理的負担を減らし、プロダクト全体の信頼感を高めます。
React Hook Form × UX設計、ぜひあなたのフォームにも取り入れてみてください。
Discussion