🧩

React Hook Formで実現する“やさしい”バリデーション設計

に公開

はじめに

どんなに正確なフォームでも、入力中に頻繁に赤字エラーが出たり、送信ボタンが押せなかったりすると、ユーザーは「自分が間違えているのか?」とストレスを感じてしまいます。

React Hook Form(以下、RHF)はバリデーションをシンプルに書ける便利なライブラリですが、「いつ」「どのように」チェックを走らせるかを意識すると、UXの質が大きく変わります。

https://react-hook-form.com/

今回は、**初学者でも実装できる“ユーザーフレンドリーなバリデーション設計”**をテーマに、

  • ボタンの非活性での導線設計
  • エラーメッセージの出し方とタイミング
  • 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の基本的な使い方についてこちらの記事で詳しく解説しています。
useFormregisterhandleSubmitやフォームのデータ操作について知りたい方はぜひご覧ください。
https://zenn.dev/nekonoko2323/articles/4c69c8e500c5d9


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 一度触れた後に随時 onBluronChangeの中間的
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+メッセージ 何が問題かを明確に伝える
チェックタイミング modetrigger 適切な瞬間にやさしく知らせる

これらを組み合わせると、「エラーで止めるフォーム」ではなく、
“ユーザーを導くフォーム” に進化します。

設計の指針

  • 何を防ぎたいのか(誤送信?入力ミス?)
  • いつ知らせたいのか(入力中?完了後?)
  • どう感じさせたいのか(安心?即時性?)

たとえば「誤送信を防ぎたい」なら、isValidisSubmittingでボタン制御。
「入力途中のストレスを減らしたい」なら、mode: "onBlur"でエラーを出すタイミングを遅らせる、など。

技術的な設定値の裏には、必ずUX上の「意図」があります。
RHFはその意図をコードで表現できる強力なツールです。


まとめ

  • React Hook Formはバリデーションを簡単にするだけでなく、体験設計をコントロールするツール
  • isValidisSubmittingを組み合わせて「押せない安心感」を作る。
  • onBlurtriggerで、ユーザーが“ちょうどいいタイミング”で気づける設計にする。
  • 「エラーを出す」ではなく、「正しい入力に導く」発想で考える。

入力がスムーズで、エラーが自然に導かれるフォームは、
使う人の心理的負担を減らし、プロダクト全体の信頼感を高めます。

React Hook Form × UX設計、ぜひあなたのフォームにも取り入れてみてください。

Discussion