HTML でフォームを作る方法
フォームは、入力欄と送信ボタンを含む <form> 要素です。各入力欄には name が必要です。値はその名前をキーにして送信されます。フォームに入力して Send を押してみてください。プレビューはどこにもデータを送らず、ブラウザが送るはずだった内容をそのまま表示します。
各部分の役割です。
actionはデータの送り先の URL、methodは送り方 (ここではpost) です。- すべての入力欄に
nameを付けます。その値は読者が入力した内容です。 <label>は画面上とスクリーンリーダーの両方で各入力欄に名前を付けます (HTML の label を参照)。requiredとtype="email"を付けると、ブラウザが送信前に入力欄をチェックします。名前を空にしたり、メールアドレスにabcと入れたりして送信してみてください。- 送信ボタンでフォームが送信されます。テキスト欄で Enter キーを押しても送信されます。
action と method: データの送り先と送り方
| 属性 | 値 | 初期値 |
|---|---|---|
action | 任意の URL | 現在のページの URL |
method | get、post、dialog | get |
enctype | application/x-www-form-urlencoded、multipart/form-data、text/plain | application/x-www-form-urlencoded |
method="get" では、入力欄が URL のクエリ文字列になります。name="q" の検索フォームなら /search?q=blue+shoes に移動します。結果をブックマークしたり共有したりできるので、検索や絞り込みにはこれが適しています。method="post" では、入力欄はリクエストの本文で送られ、アドレスバーや履歴には表示されません。ログイン、作成、変更、削除を行うものとパスワードには POST を使いましょう。
ファイルのアップロード (<input type="file">) があるフォームには method="post" と enctype="multipart/form-data" が必要です。ないとファイル名しか送信されません。method="dialog" は <dialog> の中のフォーム用で、送信するとリクエストを送る代わりにダイアログが閉じます。
送信される内容
送信されるのは name のある入力欄だけで、しかも disabled でないものに限ります。Submit を押して、入力欄とフォームが送る内容を比べてみましょう。
フォームが送るのは city、zip、source、action です。name のない入力欄、無効にした入力欄、チェックされていないチェックボックスは送られません。hidden の input は表示されませんが送信され、送信ボタンは使われたボタンなので自分の name と value を送ります。
fieldset と legend で入力欄をまとめる
<fieldset> は関連する入力欄を枠で囲み、<legend> はその見出しです。フォーカスがグループに入るとスクリーンリーダーが legend を読み上げるので、下の例のようなラジオボタンの組の意味が伝わります: 「Delivery、Standard、ラジオボタン」。
fieldset に disabled を付けると、中の入力欄がまとめて無効になり、どれも送信されません。これを外すとギフトの入力欄が使えるようになります。
組み込みの入力チェック: required、pattern など
ブラウザは送信前にこれらの属性をチェックし、最初に失敗した入力欄にメッセージを表示します。
| 属性 | チェック内容 |
|---|---|
required | 入力欄が空でない (チェックボックスならチェックされている) |
type="email"、type="url" | 値がメールアドレスや URL の形をしている |
minlength、maxlength | テキストの長さ |
min、max、step | 数値や日付の範囲 |
pattern | 値全体が正規表現に一致する |
:invalid と :valid で状態に応じて入力欄にスタイルを付けられます。たいていは :user-invalid のほうが適しています。読者が入力欄を変更して離れたとき、または送信しようとしたときにだけ適用されるので、空のフォームが開いた瞬間から真っ赤になることがありません。
pattern にはつまずきやすい点が 3 つあります。値全体に一致する必要があります (^ や $ は不要です)。入力欄が空でないときにしか動かないので、required と組み合わせます。そしてブラウザのエラーメッセージは汎用的なので、形式の説明は入力欄の横に見えるテキストで書きましょう。Chrome と Firefox は title のテキストをメッセージに追加しますが、見落とされがちです。
サーバー側の入力チェックをテストするときなど、チェックを止めたいときは <form> に novalidate を付けます。特定の送信ボタンだけ formnovalidate でチェックを飛ばすこともできます。
ブラウザの入力チェックは読者の手間を減らすためのものです。誰でもページを書き換えたり、チェックなしでリクエストを送ったりできるので、サーバーですべての値をもう一度チェックする必要があります。
setCustomValidity で独自のメッセージを出す
「2 つのパスワードが一致すること」のように属性で書けないルールは、JavaScript でメッセージを設定します。空でない独自のメッセージを持つ入力欄は不正な状態になり、空文字列を設定すると再び有効になります。
確認用の入力欄には name がないので、パスワードは 1 つだけ送信されます。
JavaScript で送信を処理する
ページを移動せずにフォームを送るには、submit を受け取って preventDefault() を呼び、FormData で入力欄を読み取ります。ボタンの click ではなく submit を受け取れば、Enter キーを含むすべての送信方法を捕まえられ、組み込みの入力チェックが通った後にだけ実行されます。
Object.fromEntries(new FormData(form)) は入力欄を普通のオブジェクトに変えます。複数の値を持てる入力欄 (同じ name を共有するチェックボックス、multiple のセレクト) には formData.getAll('name') を使いましょう。オブジェクトには最後の値しか残らないからです。
よくある間違い
nameのない入力欄。 送信データから黙って省かれます。- ラベルの代わりにプレースホルダーを使う。 読者が入力を始めるとヒントが消えます。
<label>を使いましょう。 - 送信以外の目的で
typeのない<button>を使う。 フォームの中では送信ボタンになります。 - フォームの中にフォームを置く。 フォームの入れ子は無効で、ブラウザは内側の
<form>タグを無視します。 - フォームの
submitではなく送信ボタンのclickを受け取る。 Enter キーでの送信を取りこぼします。 - サーバー側でブラウザの入力チェックを信用する。 サーバーでもう一度チェックしましょう。
- パスワードに GET を使う。 URL、履歴、サーバーのログに残ってしまいます。
よくある質問
HTML でフォームを作るにはどうすればいいですか?
入力欄を <form action="/signup" method="post"> で囲み、すべての入力欄に name と <label> を付け、最後に <button type="submit"> を置きます。フォームを送信すると、ブラウザは name=value の組を 1 つずつ action の URL に送ります。
フォームの GET と POST の違いは何ですか?
method="get" (初期値) は入力内容を /search?q=shoes のように URL に入れるので、ブックマークできるべき検索や絞り込みに向いています。method="post" はリクエストの本文で送るので、ログイン、会員登録、データを変更する処理に使います。
フォームの入力欄が送信されないのはなぜですか?
name 属性がないか、disabled になっています。送信されるのは name があり、無効になっていない入力欄だけです。チェックされていないチェックボックスやラジオボタンも丸ごと送信されません。
fieldset と legend は何に使いますか?
<fieldset> は関連する入力欄をまとめ、<legend> はそのグループの見出しです。フォーカスがグループに入るとスクリーンリーダーが legend を読み上げるので、ラジオボタンのグループの意味が伝わります。fieldset に disabled を付けると、中の入力欄がすべて無効になります。
JavaScript を使わずに HTML だけでフォームの入力チェックをするには?
required、type="email"、minlength、maxlength、min、max、pattern などの属性を使います。ブラウザは送信を止め、最初の不正な入力欄にメッセージを表示します。これらのチェックは読者のブラウザで動くので回避できます。サーバー側でも必ずチェックしましょう。
フォームを送信したときにページが再読み込みされないようにするには?
フォームの submit イベントを受け取って event.preventDefault() を呼び、fetch で自分でデータを送ります: form.addEventListener('submit', (e) => { e.preventDefault(); fetch(form.action, { method: 'POST', body: new FormData(form) }); })。