フォーム送信イベントとは何か
フォーム送信イベントは、ユーザーがフォームを送ろうとした瞬間に発火する “submit” イベントのことです。ここが重要です:submit は「実際の送信前」に発火するため、検証や送信のキャンセル、AJAX 送信への置き換えができます。送信を止めるには e.preventDefault()、ブラウザの組み込み検証を活かすなら checkValidity() と requestSubmit() の使い分けが鍵になります。
送信イベントの基本(submit の監視とキャンセル)
最小の監視とキャンセル
<form id="f">
<input name="email" type="email" required>
<button>送信</button>
</form>
<script>
f.addEventListener("submit", (e) => {
e.preventDefault(); // 実際の送信を止める
console.log("送信前に介入できます");
});
</script>
HTMLここが重要です:submit はフォーム全体に対して一回発火します。preventDefault() を呼ぶと、ブラウザによるページ遷移や HTTP 送信を止めて、独自処理(検証・AJAX)へ置き換えられます。
Enter キーやボタンでの送信
<form id="f">
<input name="q" placeholder="検索"> <!-- フォーカス中に Enter で送信 -->
<button type="submit">送信</button> <!-- 明示的に送信 -->
</form>
HTMLここが重要です:入力中の Enter、type=”submit” のボタン、またはフォーム内で唯一のボタンが “送信トリガー” になります。submit の扱いは同じなので、イベント一箇所で統制できます。
組み込み検証とイベントの順序(checkValidity と requestSubmit)
組み込み検証を使う送信
<form id="f">
<input name="email" type="email" required>
<button type="submit">送信</button>
</form>
<script>
f.addEventListener("submit", (e) => {
if (!f.checkValidity()) {
e.preventDefault(); // エラーがあれば送信を止める
// ブラウザがバブルのエラー表示を行う(typeやrequiredに基づく)
return;
}
// ここまで来たら入力は妥当
});
</script>
HTMLここが重要です:checkValidity() は HTML 属性にもとづく検証(required、type、min/max、pattern 等)を実行します。失敗時に preventDefault で止めるのが定石。成功時だけ送信や AJAX へ進みます。
プログラムから“検証して送信”する
<script>
// ボタンや別UIから送信したいとき
if (f.reportValidity()) { // 画面に検証メッセージも表示
f.requestSubmit(); // ネイティブの送信を起動(submitが発火)
}
</script>
HTMLここが重要です:requestSubmit() は「送信ボタンを押したのと同じ」扱いになり、検証を通した上で submit が発火します。f.submit() は検証をスキップして即送信するので、通常は使いません(誤送信の原因になります)。
AJAX 送信に置き換える(FormData と fetch)
送信を止めて非同期送信する基本形
<form id="f" action="/api/submit" method="post">
<input name="email" type="email" required>
<input name="name" required>
<button>送信</button>
</form>
<script>
f.addEventListener("submit", async (e) => {
e.preventDefault(); // ページ遷移を止める
if (!f.checkValidity()) return; // 検証NGなら何もしない
const fd = new FormData(f); // name→value のペアを収集
const res = await fetch(f.action, {
method: f.method,
body: fd,
});
if (res.ok) {
alert("送信に成功しました");
f.reset();
} else {
alert("送信に失敗しました");
}
});
</script>
HTMLここが重要です:FormData は実送信と同じ形で値を集め、ファイルもそのまま送れます。成功時に reset で初期化するか、エラー時はメッセージとフォーカス誘導で再入力を助けます。
JSON 送信が必要な場合
<script>
f.addEventListener("submit", async (e) => {
e.preventDefault();
if (!f.checkValidity()) return;
const data = Object.fromEntries(new FormData(f));
const res = await fetch("/api/submit-json", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
// 後続は前例と同様
});
</script>
HTMLここが重要です:API が JSON を期待するなら、FormData をオブジェクト化して JSON 化します。checkbox の未チェックはキーなし(存在しない)になるため、必要なら明示的に false を補完する設計にしましょう。
どのボタンが押されたかを知る(submitter の活用)
複数の送信ボタンを区別する
<form id="f">
<button name="action" value="save">保存</button>
<button name="action" value="delete">削除</button>
</form>
<script>
f.addEventListener("submit", (e) => {
const btn = e.submitter; // 押されたボタン(対応ブラウザ)
const action = btn?.value || "save";
e.preventDefault();
console.log("押されたアクション:", action);
});
</script>
HTMLここが重要です:submitter で「どのボタンが送信を起動したか」が分かります。対応が必要な環境では、クリック時に外部変数へ退避してから submit 内で参照する方法でも同じことができます。
よく使う補助テクニック(フォーカス、エラー表示、進行中のブロック)
エラー時はフォーカスを当てて再入力を助ける
<script>
f.addEventListener("submit", (e) => {
if (!f.checkValidity()) {
e.preventDefault();
const firstInvalid = f.querySelector(":invalid");
firstInvalid?.focus();
}
});
</script>
HTMLここが重要です:最初のエラー要素へ focus() を合わせるだけで、学習負担が大きく下がります。ネイティブ検証と組み合わせると効果的です。
二重送信の防止(押してから完了まで無効化)
<script>
f.addEventListener("submit", async (e) => {
e.preventDefault();
if (!f.checkValidity()) return;
const btn = e.submitter;
btn.disabled = true;
try {
// fetch などの送信
} finally {
btn.disabled = false;
}
});
</script>
HTMLここが重要です:送信中にボタンを無効化すると、連打や二重送信を防げます。UI 上はローディング表示と組み合わせるとさらに親切です。
送信の発火源(requestSubmit / ネイティブ / 手動)を正しく選ぶ
ユーザー操作と同等の送信を起こす
<script>
// 検証を通してから、submit(イベントも)を正規に発火
if (f.reportValidity()) f.requestSubmit();
</script>
HTMLここが重要です:ユーザー操作に近い形で送信したいなら requestSubmit。一方 f.submit() は検証やイベントをスキップするので、緊急時の内部送信以外は避けるのが安全です。
まとめ
フォーム送信イベントは「送信直前に介入できる唯一のタイミング」です。基本は submit を監視し、e.preventDefault() で送信を止めて検証や AJAX 送信へ置き換える。HTML の組み込み検証は checkValidity/reportValidity と requestSubmit を組み合わせると自然な体験になります。送信データは FormData(または JSON)で扱い、エラー時は最初の不正要素へフォーカス、進行中はボタン無効化で二重送信を防止。複数ボタンの区別は e.submitter で取得して分岐。これらを押さえれば、初心者でも“壊れない・親切で近代的”なフォーム送信処理が書けます。
