突然ですが、次のようなHTMLファイルをブラウザで開いてみましょう。
<!DOCTYPE html>
<head></head>
<body>
<form>
<p>
<input type='text'>
</p>
<form>
<p>
<input type='text'>
</p>
</form>
</form>
</body>
開いたら開発者ツールでDOMをインスペクトしてみましょう。
なんと内側のformタグがいなくなってしまっています。
実はHTMLの仕様として、入れ子のformタグは許可されていません。(詳細な話はこちらにのっています→ html - formタグの入れ子とブラウザーの解釈 - スタック・オーバーフロー)
この仕様を知らなかったため、業務で開発しているWEBアプリにバグを入れてしまいました…。
なぜformがなくなってしまうのかわからずフロントエンドで使っているライブラリを疑ってみたり、ダミーのフォームを入れてみたり、いろいろと試行錯誤してずいぶん手間取ってしまいました…。
とはいえ、自分が実際そうしてしまったようにフォームの中にフォームを作りたくなる場合もあるかと思います。たとえば、次のような感じ?メッセージの一覧画面をイメージしてください。
<!DOCTYPE html>
<head></head>
<form>
<ul>
<li>
<input type="checkbox">
項目1
<input type="button" value="アーカイブ">
<form style="display: inline">
<select>
<option value="" selected disabled>削除理由を選択…</option>
<option value="1">理由1</option>
<option value="1">理由2</option>
</select>
<input type="submit" value="削除">
</form>
</li>
<li>
<input type="checkbox">
項目2
<input type="button" value="アーカイブ">
<form style="display: inline">
<select>
<option value="" selected disabled>削除理由を選択…</option>
<option value="1">理由1</option>
<option value="1">理由2</option>
</select>
<input type="submit" value="削除">
</form>
</li>
<li>
<input type="checkbox">
項目3
<input type="button" value="アーカイブ">
<form style="display: inline">
<select>
<option value="" selected disabled>削除理由を選択…</option>
<option value="1">理由1</option>
<option value="1">理由2</option>
</select>
<input type="submit" value="削除">
</form>
</li>
</ul>
<input type="submit" value="チェックボックスをつけたものをまとめてアーカイブ">
</form>
下の画像のように、リスト要素ひとつひとつについてフォームがあり、さらに外にリスト要素をまとめて操作できるフォームがあるといった具合。
しかし、前述の通りformタグ内にformタグがあるという状態は許容されていないため、これではおかしくなってしまいます。
input要素は何もしなければ祖先要素のうち、一番近いフォームの部品として働くのですが、HTML5ではinput要素にform
という属性があります。これを使えば、所属させたいフォームをつくるformタグの子孫にしなくてもよくなります。
<input type="text" form="form-form">
<form id="form-form"></form>
とすれば、一行目のテキストボックスは"#form-form"のフォームの部品となってくれます。
これがわかったうえで先程のメッセージ一覧画面をちゃんと動くように直してみましょう。
<!DOCTYPE html>
<head></head>
<ul>
<li>
<input type="checkbox" form="bulk-archive">
項目1
<input type="button" value="アーカイブ">
<form style="display: inline">
<select>
<option value="" selected disabled>削除理由を選択…</option>
<option value="1">理由1</option>
<option value="1">理由2</option>
</select>
<input type="submit" value="削除">
</form>
</li>
<li>
<input type="checkbox" form="bulk-archive">
項目2
<input type="button" value="アーカイブ">
<form style="display: inline">
<select>
<option value="" selected disabled>削除理由を選択…</option>
<option value="1">理由1</option>
<option value="1">理由2</option>
</select>
<input type="submit" value="削除">
</form>
</li>
<li>
<input type="checkbox" form="bulk-archive">
項目3
<input type="button" value="アーカイブ">
<form style="display: inline">
<select>
<option value="" selected disabled>削除理由を選択…</option>
<option value="1">理由1</option>
<option value="1">理由2</option>
</select>
<input type="submit" value="削除">
</form>
</li>
</ul>
<form>
<input id="bulk-archive" type="submit" value="チェックボックスをつけたものをまとめてアーカイブ">
</form>
メッセージをまとめて操作するフォームの中に各メッセージを操作するフォームがあるのではなく、フラットな構造になりました。これで、勝手にformタグがいなくなったりすることはありません!
ほかに「Ajaxを使う」といった解決法もありますが、HTMLだけで解決してしまったほうがシンプルかなーと思います。