解説
JavaScriptで送るとrequiredが効かない?requestSubmitとsubmitの経路を比べよう
フォームの送信メソッドで、制約検証・submitイベント・送信ボタンの値がどう違うかを比較。外部通信しない作例で空欄と入力済みを試そう。

入力必須のはずの欄が、JavaScriptから送ると空のまま通ってしまった。送信ボタンを押す場合と、form.submit()を呼ぶ場合では、ブラウザが通る経路が違うよ。
この記事は、フォームとイベント処理の基本が分かる人向け。requestSubmit()とsubmit()を比べ、制約検証、submitイベント、送信に使うボタンの値を分けて確認する。作例は架空のメモだけを使い、外部サーバーへ通信しない。
requestSubmitは、送信ボタンに近い経路
制約検証は、requiredや入力型などHTMLで指定された条件をブラウザが確認する仕組み。requestSubmit()はこの確認を行い、通った場合にフォームのsubmitイベントへ進む。ここでは検証を省くnovalidateや、送信ボタンのformnovalidateを指定しない条件で比べるよ。
<form id="sample" action="about:blank" target="empty-frame">
<label for="memo">メモ(必須)</label>
<input id="memo" name="memo" required>
<button id="save" type="submit" name="intent" value="save">保存</button>
</form>
<iframe name="empty-frame" title="空の練習用送信先" hidden></iframe>
const form = document.querySelector('#sample');
const save = document.querySelector('#save');
form.requestSubmit(save);
空欄なら入力欄でinvalidイベントが発生し、通常はsubmitイベントへ進まない。入力済みで条件を満たせば、submitイベントが発生するよ。イベントのpreventDefault()で標準の送信を止めることもできる。
submitは、同じ確認を呼ばない
form.submit();
この直接の呼び出しは制約検証を起動せず、submitイベントも発生させない。そのため、submitイベントの中だけに書いた確認処理や、送信を止めるpreventDefault()は実行されないんだ。
| 比較すること | requestSubmit(save) | submit() |
|---|---|---|
| HTMLの制約検証 | 行う | 起動しない |
| 条件を満たしたときのsubmitイベント | 発生する | 発生しない |
| 指定した送信ボタンの名前と値 | 送信データに含められる | そのボタンを指定する引数はない |
submit()でチェックを飛ばせるのは、サーバー側の確認まで不要になるという意味ではない。受け付ける側でも、必要な項目と値を検証する必要があるよ。
ボタンを指定したかも分けて見る
requestSubmit(save)の引数は、そのフォームに属する送信ボタン。今回ならintent=saveを含む送信の経路になる。引数なしのrequestSubmit()では、フォーム自身が送信元として扱われ、どこかの送信ボタンが自動で選ばれるわけではない。
イベントでフォームデータを作って表示するなら、押されたボタンも渡せる。
form.addEventListener('submit', event => {
event.preventDefault();
const data = new FormData(form, event.submitter);
console.log([...data.entries()]);
});
このコードはsubmitイベントを通る経路で使う例。直接のsubmit()までこのイベントで止められるとは考えないでね。実際の送信先に置き換える前に、どの経路を使う設計かを確認しよう。
ページ内で空欄と入力済みを比べる
- 空欄のまま「requestSubmitで試す」を押す。invalidが1、submitが0になる。
- 「submitで試す」を押す。空欄でもデータが作られ、submitイベントは0のまま。
- 「memoを入力」の後にrequestSubmitで試す。submitが1になり、memoの値とintent=saveが表示される。
- 同じ入力でsubmitを試し、intentの組がないことを見る。
- 「最初から試す」で空欄と未実行の表示へ戻す。
作例では、requestSubmitのsubmitイベントで通信を止め、FormDataを作って記録する。直接のsubmitはそのイベントを通らないため、送信先を空の子フレームのabout:blankにしている。外部への送信先は設けていないよ。二つの比較ボタンを押すたびに記録を初期化し、そのボタンで実行した一回分を表示する。
submit is not a functionなら名前も調べる
入力欄やボタンのnameまたはidにsubmitを付けると、フォームのsubmitメソッドがその要素で隠れる場合がある。今回の作例で直接送信に使うHTMLFormElement.prototype.submit.call(form)は、フォームのプロトタイプにあるメソッドを呼ぶ書き方だよ。
まずは入力項目の名前をintentなど役割の分かるものにし、ブラウザ標準の機能と衝突していないか調べよう。すべての問題を別の送信方式へ置き換えて解決するより、検証とイベントのどちらが実行されたかを追うと原因を絞りやすいね。
基本の条件はrequiredとemailの検証、ボタン本来の役割はtypeとフォーム送信で確認できる。
2026年11月1日にMDNを確認し、空欄・入力済みの両方式、イベントとフォームデータ、内側のリセットをChromiumで検証した。幅240・319・1280pxで操作し、allow-scripts allow-formsのsandbox内でも動作を確認している。
動かしてみよう:requestSubmit / submit
設定や入力を切り替え、表示と結果を比べよう。最初から試すボタンで戻せるよ。

みんなのコメント 0
感想や、試してみたことを聞かせてね。コメント・返信は承認後に公開されます。
最初のコメントをどうぞ。