- HTML
HTML select・checkbox・radioの書き方|初期値と値取得
select・checkbox・radioは、どれも「あらかじめ用意した選択肢から選んでもらう」ためのフォーム部品で、初期値はselectならselected属性、checkboxとradioならchecked属性で決めます。 値の取得は、JavaScriptならvalue(selectとradio)とchecked(checkbox)、まとめて取るならFormDataを使います。
この記事では、3つの部品を「書き方・初期値・取得・設定・変更イベント・送信される値」の6つの観点で横に並べて比べます。コードはすべてjQueryなしの素のJavaScriptで統一し、Playwright 1.56.0 に同梱の Chromium 141 で実際に動かした結果をそのまま載せています。「チェックを外したcheckboxがサーバーに届かない」「valueを書き忘れたらonが届いた」といった、つまずきやすい挙動も実行結果で確かめます。
select・checkbox・radioの早見表
まずは3つの部品を1枚で比べます。迷ったときはこの表だけ見れば、書き方から送信される値までたどれます。
| 観点 | select(プルダウン) | checkbox(チェックボックス) | radio(ラジオボタン) |
|---|---|---|---|
| 選べる数 | 1つ(multipleで複数) |
0個以上(それぞれ独立) | 同じnameの中で1つ |
| HTMLの書き方 | <select name>の中に<option value> |
<input type="checkbox" name value> |
<input type="radio" name value>を同じnameで並べる |
| 初期値の属性 | <option selected> |
checked |
checked |
| 初期値を書かないとき | 先頭のoptionが選ばれる |
未チェック | どれも未選択 |
| JavaScriptで取得 | select.value |
input.checked(true / false) |
form.elements.名前.value |
| 複数の値を取得 | [...select.selectedOptions] |
querySelectorAll(":checked") |
(1つだけ) |
| FormDataで取得 | fd.get("名前")、複数はfd.getAll("名前") |
fd.getAll("名前") |
fd.get("名前") |
| JavaScriptで設定 | select.value = "m" |
input.checked = true |
form.elements.名前.value = "red" |
| 変更イベント | change |
change |
change(選ばれた側だけ) |
| 送信される値 | 選ばれたoptionのvalue |
チェックありのときだけvalue |
選ばれた1つのvalue |
valueを省略すると |
optionの表示テキスト |
文字列on |
文字列on |
| 何も選ばれていないとき | (単一は必ず何か選ばれる) | 名前ごと送信されない | 名前ごと送信されない |
| 必須にする | required+先頭をvalue="" |
required(その1個が必須) |
グループのどれか1つにrequired |
使い分けの目安は次のとおりです。
| 選んでもらう内容 | 向いている部品 | 理由 |
|---|---|---|
| 2〜5個から1つ | radio | 選択肢が最初から全部見える |
| 6個以上から1つ | select | 場所を取らない |
| 複数を選ぶ | checkbox | 選んだ状態がひと目でわかる |
| はい・いいえの1項目 | checkbox 1個 | クリック1回で切り替えられる |
| 数十個から複数 | checkboxの一覧(またはselect multiple) |
select multipleはCtrlキー操作が必要になる |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「HTML select・checkbox・radioの書き方|初期値と値取得」
コピペで動く完成形のフォーム
3つの部品を1つのフォームにまとめた見本です。この記事の実行結果は、すべてこのHTMLを使っています。ファイル名をform.htmlとして保存すれば、そのまま開けます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>select・checkbox・radio の見本</title>
</head>
<body>
<form id="order" action="/echo" method="post">
<p>
<label for="size">サイズ</label>
<select id="size" name="size">
<option value="">選んでください</option>
<option value="s">S</option>
<option value="m" selected>M</option>
<option value="l">L</option>
</select>
</p>
<p>
<label for="tags">タグ(複数可)</label>
<select id="tags" name="tags" multiple size="3">
<option value="new" selected>新着</option>
<option value="sale">セール</option>
<option value="gift" selected>ギフト</option>
</select>
</p>
<fieldset>
<legend>色(1つ選ぶ)</legend>
<label><input type="radio" name="color" value="red"> 赤</label>
<label><input type="radio" name="color" value="blue" checked> 青</label>
<label><input type="radio" name="color" value="green"> 緑</label>
</fieldset>
<fieldset>
<legend>オプション(複数可)</legend>
<label><input type="checkbox" name="option" value="wrap" checked> ラッピング</label>
<label><input type="checkbox" name="option" value="card"> メッセージカード</label>
<label><input type="checkbox" name="option" value="bag" checked> 手さげ袋</label>
</fieldset>
<p>
<input type="hidden" name="mail" value="0">
<label><input type="checkbox" name="mail" value="1"> お知らせメールを受け取る</label>
</p>
<p>
<label><input type="checkbox" name="agree"> 利用規約に同意する</label>
</p>
<button type="submit">送信</button>
<button type="reset">リセット</button>
</form>
<script>
const form = document.querySelector("#order");
form.addEventListener("change", (e) => {
console.log("change:", e.target.name, "=",
e.target.type === "checkbox" ? e.target.checked : e.target.value);
});
</script>
</body>
</html>
このフォームには、あとで説明する3つの仕掛けを入れてあります。
mail:同じ名前のhiddenを前に置き、未チェックでも値が届くようにしているagree:わざとvalueを書いていない(onが届くことを確かめるため)tags:select multipleで初期値を2つ選んでいる
selectの書き方と初期値
基本の形
selectはoptionを並べて作ります。サーバーに届くのはoptionのvalueで、画面に見えるのはタグの間のテキストです。
<label for="size">サイズ</label>
<select id="size" name="size">
<option value="">選んでください</option>
<option value="s">S</option>
<option value="m" selected>M</option>
<option value="l">L</option>
</select>
| 属性 | 付ける場所 | はたらき |
|---|---|---|
name |
select |
送信するときの項目名。書かないと送信されない |
value |
option |
送信される値。省略すると表示テキストが値になる |
selected |
option |
初期値にする |
disabled |
option / select |
選べなくする。選ばれていても送信されない |
multiple |
select |
複数選択にする |
size |
select |
一度に見せる行数 |
required |
select |
必須にする |
初期値はoptionにselectedを付ける
初期値にしたいoptionにselectedを書きます。selectedをどこにも書かなければ、先頭のoptionが選ばれた状態になります。
よく見る「選んでください」という案内は、先頭にvalue=""のoptionを置く形で作ります。requiredと組み合わせると、案内のまま送信しようとしたときにブラウザーが止めてくれます。
<select name="size" required>
<option value="">選んでください</option>
<option value="s">S</option>
<option value="m">M</option>
</select>
グループ分けはoptgroup
選択肢が多いときはoptgroupで見出しを付けられます。見出し自体は選べません。
<select name="item">
<optgroup label="文房具">
<option value="pen">ペン</option>
<option value="note">ノート</option>
</optgroup>
<optgroup label="備品">
<option value="chair">いす</option>
<option value="desk">机</option>
</optgroup>
</select>
複数選択はmultiple
multipleを付けるとリスト形式になり、CtrlキーやShiftキーを押しながら複数を選べます(macOSはCommandキー)。初期値は複数のoptionにselectedを付けます。
<select name="tags" multiple size="3">
<option value="new" selected>新着</option>
<option value="sale">セール</option>
<option value="gift" selected>ギフト</option>
</select>
キー操作に慣れていない人には伝わりにくいので、選択肢が少ないときはcheckboxを並べるほうが選びやすくなります。
checkboxの書き方と初期値
基本の形
checkboxは1個ずつ独立していて、それぞれがオン・オフを持ちます。複数から選んでもらうときは、同じnameでvalueだけ変えて並べます。
<fieldset>
<legend>オプション(複数可)</legend>
<label><input type="checkbox" name="option" value="wrap" checked> ラッピング</label>
<label><input type="checkbox" name="option" value="card"> メッセージカード</label>
<label><input type="checkbox" name="option" value="bag" checked> 手さげ袋</label>
</fieldset>
初期値はchecked
最初からチェックを入れておきたいものにcheckedを書きます。checked="checked"と書いても同じ意味です。checked="false"と書いてもチェックは入ったままになる点だけ覚えておいてください。属性は「あるか、ないか」だけで判定されるためです。チェックを外しておきたいときは、属性そのものを書きません。
1個だけのcheckbox
「同意する」のような1項目は、checkboxを1個だけ置きます。必須にするにはrequiredを付けます。
<label><input type="checkbox" name="agree" value="yes" required> 利用規約に同意する</label>
radioの書き方と初期値
基本の形
radioは、同じnameを持つもの同士が1つのグループになり、その中で1つだけ選べます。nameが違うと別のグループになり、同時に選べてしまうので、つづりをそろえてください。
<fieldset>
<legend>色(1つ選ぶ)</legend>
<label><input type="radio" name="color" value="red"> 赤</label>
<label><input type="radio" name="color" value="blue" checked> 青</label>
<label><input type="radio" name="color" value="green"> 緑</label>
</fieldset>
初期値はchecked
初期値にしたい1つにcheckedを書きます。どれにも書かなければ、何も選ばれていない状態で始まります。radioは一度どれかを選ぶと、利用者の操作では「未選択」に戻せません。「選ばない」という答えもありうるなら、「指定なし」という選択肢を1つ用意すると親切です。
同じグループの2つにcheckedを書いた場合、手元のChromium 141ではあとに書いたほうが選ばれました(後述の実行結果のrr)。
入力しやすくする基本:labelとfieldset
labelで文字もクリックできるようにする
checkboxとradioは的が小さいので、labelで文字と結び付けると、文字をクリックしても切り替わるようになります。結び付け方は2通りです。
<!-- 方法1:label で input を包む -->
<label><input type="checkbox" name="agree" value="yes"> 同意する</label>
<!-- 方法2:for と id をそろえる -->
<input type="checkbox" id="agree" name="agree" value="yes">
<label for="agree">同意する</label>
labelがあるときとないときで、文字をクリックした結果を比べました。
labelあり: true / labelなし: false / a.labels.length=1
labelで結び付けたほうだけ、文字のクリックでチェックが入っています。読み上げソフトも、labelの文字を部品の名前として読み上げます。
fieldsetとlegendでグループに名前を付ける
radioやcheckboxのまとまりはfieldsetで囲み、legendに質問文を書きます。「赤・青・緑」だけでは何を聞かれているのかわかりませんが、legendに「色(1つ選ぶ)」と書いておけば、見た目でも読み上げでも質問が伝わります。
| 工夫 | 書き方 | 効果 |
|---|---|---|
| 文字もクリック可能にする | labelで包む、またはforとid |
押しやすくなる。読み上げにも対応 |
| グループに質問文を付ける | fieldsetとlegend |
何を選ぶのかが伝わる |
| まとめて選べなくする | fieldsetにdisabled |
中の部品が一括で無効になる |
| 必須を伝える | requiredと、文字での「必須」表示 |
ブラウザーの検証と見た目の両方で伝わる |
| 選択肢を縦に並べる | CSSでdisplay: blockなど |
スマートフォンで押しやすい |
JavaScriptで値を取得する
部品ごとに取得する
フォームの中の部品は、form.elements.名前で取り出せます。完成形のフォームを開いた直後(初期値のまま)に、次のコードを実行しました。
const f = document.querySelector("#order");
const size = f.elements.size;
const tags = f.elements.tags;
console.log(size.value); // 選ばれている value
console.log(size.selectedIndex); // 何番目か(0始まり)
console.log(size.selectedOptions[0].text); // 表示テキスト
console.log(tags.value); // multiple でも最初の1つだけ
console.log([...tags.selectedOptions].map((o) => o.value));
console.log(f.elements.color.value); // radio グループの値
console.log(f.querySelector('input[name="color"]:checked').value);
console.log([...f.querySelectorAll('input[name="option"]:checked')].map((c) => c.value));
console.log(f.elements.agree.checked); // checkbox のオン・オフ
console.log(f.elements.agree.value); // value 属性の値
実行結果(Chromium 141):
size.value="m"
size.selectedIndex=2
size.selectedOptions[0].text=M
tags.value="new"
tags.selectedOptions=["new","gift"]
elements.color.value="blue"
querySelector(color:checked).value="blue"
option:checked=["wrap","bag"]
agree.checked=false
agree.value="on"
ここから読み取れるポイントは3つです。
select multipleのvalueは最初の1つしか返さない。 全部ほしいときはselectedOptionsを使います- radioグループは
form.elements.名前.valueで選ばれた値が取れる。 同じ名前の部品が複数あるとelementsはRadioNodeListというまとまりを返し、そのvalueが選択中の値になります。何も選ばれていないときは空文字です - checkboxの
valueはチェックの有無と関係がない。agreeは未チェックなのにvalueはonを返しています。オン・オフは必ずcheckedで調べます
取得方法の逆引き表
| やりたいこと | コード |
|---|---|
| selectの選択値 | select.value |
| selectの表示テキスト | select.selectedOptions[0].text |
| select multipleの全選択値 | [...select.selectedOptions].map((o) => o.value) |
| radioの選択値(フォーム内) | form.elements.color.value |
| radioの選択値(フォーム外) | document.querySelector('input[name="color"]:checked')?.value |
| checkboxのオン・オフ | input.checked |
| チェック済みcheckboxの値一覧 | [...form.querySelectorAll('input[name="option"]:checked')].map((c) => c.value) |
| チェックされた数 | form.querySelectorAll('input[name="option"]:checked').length |
| フォーム全体をまとめて | new FormData(form) |
フォームの外にあるradioで何も選ばれていないと、querySelectorはnullを返します。?.valueと書いておくと、エラーで止まらずundefinedになります。
FormDataでまとめて取得する
送信される値がそのまま手に入る
FormDataは、フォームが送信するときの「名前と値の組」をそのまま取り出せる仕組みです。部品ごとの取り方を覚えなくても、送信内容と同じものが手に入るのが利点です。
const fd = new FormData(document.querySelector("#order"));
for (const [name, value] of fd) {
console.log(name + "=" + value);
}
初期値のままの実行結果:
size=m
tags=new
tags=gift
color=blue
option=wrap
option=bag
mail=0
tagsとoptionが2行ずつ出ています。複数選ばれた項目は、同じ名前で複数の組になります。一方、未チェックのagreeは一覧に出てきません。
複数選択はgetAllで取る
getは最初の1つだけ、getAllは全部を配列で返します。
const fd = new FormData(document.querySelector("#order"));
console.log(fd.get("size"));
console.log(fd.get("tags"));
console.log(fd.getAll("tags"));
console.log(fd.getAll("option"));
console.log(fd.get("color"));
console.log(fd.getAll("mail"));
console.log(fd.get("agree"));
console.log(fd.has("agree"));
get(size)="m"
get(tags)="new"
getAll(tags)=["new","gift"]
getAll(option)=["wrap","bag"]
get(color)="blue"
getAll(mail)=["0"]
get(agree)=null
has(agree)=false
checkboxのグループとselect multipleは、どちらもgetAllで配列として取れます。 1つも選ばれていなければgetAllは空の配列を返すので、そのままlengthやmapを使えます。
Object.fromEntriesは複数の値が1つになる
FormDataを手軽にオブジェクトへ変えるObject.fromEntriesは便利ですが、同じ名前が複数あると最後の1つだけが残ります。
console.log(JSON.stringify(Object.fromEntries(new FormData(form))));
{"size":"m","tags":"gift","color":"blue","option":"bag","mail":"0"}
tagsはnewとgiftの2つを選んでいたのにgiftだけ、optionもbagだけになりました。複数選択を含むフォームでは、次のようにgetAllで補います。
const fd = new FormData(form);
const data = Object.fromEntries(fd);
data.tags = fd.getAll("tags");
data.option = fd.getAll("option");
data.agree = fd.has("agree");
JavaScriptで値を設定する
設定の書き方
| やりたいこと | コード |
|---|---|
| selectを選ぶ | select.value = "s" |
| selectを番号で選ぶ | select.selectedIndex = 0 |
| select multipleを選び直す | for (const o of select.options) o.selected = values.includes(o.value) |
| radioを選ぶ | form.elements.color.value = "red" |
| checkboxをオンにする | input.checked = true |
| checkboxをすべてオンにする | form.querySelectorAll('input[name="option"]').forEach((c) => (c.checked = true)) |
| 初期値に戻す | form.reset() |
const f = document.querySelector("#order");
f.elements.size.value = "s";
f.elements.color.value = "red";
f.elements.agree.checked = false;
for (const o of f.elements.tags.options) {
o.selected = o.value === "sale";
}
設定後に読み直した結果:
size=s
color=red
agree=false
tags=["sale"]
存在しない値を設定すると未選択になる
select.valueに、どのoptionにもない値を入れると、何も選ばれていない状態になります。
const s = document.querySelector("#size");
s.value = "xl";
console.log(s.value, s.selectedIndex);
value="" selectedIndex=-1
サーバーから受け取った値を初期値として入れるときは、設定したあとにselectedIndexが-1になっていないかを確かめると、選択肢にない値に早く気づけます。
checked属性とcheckedプロパティは別もの
JavaScriptでinput.checked = trueとしても、HTMLのchecked属性は増えません。
const c = document.querySelector('input[name="agree"]');
c.checked = true;
console.log(c.checked, c.defaultChecked, c.hasAttribute("checked"), c.matches(":checked"));
checked=true defaultChecked=false hasAttribute=false matches(:checked)=true
| 見ているもの | 意味 | 調べ方 |
|---|---|---|
checked属性 |
初期値(リセットで戻る先) | input.defaultChecked / hasAttribute("checked") |
checkedプロパティ |
今の状態 | input.checked / CSSの:checked |
今の状態を知りたいときはcheckedプロパティか:checkedを使います。 [checked]という属性セレクターは初期値を見ているので、利用者が操作したあとの状態とは一致しません。selectのselected属性とoption.selectedプロパティも同じ関係です。
reset()で初期値に戻る
form.reset()(またはリセットボタン)は、HTMLに書いたselectedとcheckedの状態に戻します。いろいろ操作したあとに実行した結果です。
size=m
tags=new
tags=gift
color=blue
option=wrap
option=bag
mail=0
最初のFormDataとまったく同じ内容に戻りました。
変更イベントはchangeで受け取る
3つともchangeでそろえる
select・checkbox・radioは、利用者が選び直すたびにchangeイベントが発生します。フォームに1つだけリスナーを付ければ、中の部品すべての変更をまとめて受け取れます。
const form = document.querySelector("#order");
form.addEventListener("change", (e) => {
console.log("change:", e.target.name, "=",
e.target.type === "checkbox" ? e.target.checked : e.target.value);
});
サイズをLに、色を緑に、同意にチェック、お知らせメールにチェック、メッセージカードの文字をクリック、の順に操作したときの出力です。
change: size = l
change: color = green
change: agree = true
change: mail = true
change: option = true
radioのchangeは、新しく選ばれた側だけで発生します。選択が外れた側(ここでは青)では発生しません。「外れたとき」に処理をしたい場合は、グループ全体のchangeで今の値を読み直します。
inputイベントも3つの部品で発生し、手元の確認ではinput、changeの順でした。
s input
s change
c input
c change
r2 input
r2 change
JavaScriptで値を変えてもchangeは発生しない
前の節でsize.value = "s"などを実行したとき、changeのログは1行も出ませんでした。changeは利用者の操作に対して発生するイベントで、スクリプトからの代入では発生しません。 代入のあとにも同じ処理を走らせたいときは、自分でイベントを送ります。
const s = document.querySelector("#size");
s.value = "m";
s.dispatchEvent(new Event("change", { bubbles: true }));
change: size = m
bubbles: trueを付けると、フォームに付けたリスナーまでイベントが届きます。
連動の例:全選択のcheckbox
「すべて選ぶ」で下の項目をまとめて切り替え、一部だけ選ばれているときは横棒の表示(indeterminate)にする例です。
<label><input type="checkbox" id="all"> すべて選ぶ</label>
<fieldset id="items">
<legend>備品</legend>
<label><input type="checkbox" name="item" value="pen"> ペン</label>
<label><input type="checkbox" name="item" value="note"> ノート</label>
<label><input type="checkbox" name="item" value="clip"> クリップ</label>
</fieldset>
<script>
const all = document.querySelector("#all");
const items = [...document.querySelectorAll('input[name="item"]')];
all.addEventListener("change", () => {
items.forEach((c) => (c.checked = all.checked));
});
document.querySelector("#items").addEventListener("change", () => {
const n = items.filter((c) => c.checked).length;
all.checked = n === items.length;
all.indeterminate = n > 0 && n < items.length;
});
</script>
indeterminateは見た目だけの状態で、HTMLの属性では指定できず、JavaScriptからだけ設定できます。送信内容にも影響しません。次の結果のとおり、indeterminateがtrueでもcheckedがfalseなら何も送られません。
checked=false indeterminate=true 送信=[]
送信される値を確かめる
POSTで実際に送ってみる
受け取った内容をそのまま返す小さなサーバーをNode.js 22で立て、完成形のフォームから送信しました。初期値のまま「お知らせメールを受け取る」だけチェックを入れて送った結果です。
POST /echo
size=m&tags=new&tags=gift&color=blue&option=wrap&option=bag&mail=0&mail=1
methodをgetに変え、何も操作せずに送った結果です。
GET /echo?size=m&tags=new&tags=gift&color=blue&option=wrap&option=bag&mail=0
どちらもFormDataで見た内容と同じ並びです。複数選択はtags=new&tags=giftのように同じ名前が繰り返される形で届きます。サーバー側では、同じ名前の値を配列として受け取る書き方が、言語やフレームワークごとに用意されています。なお、PHPのように名前の末尾に[]を付ける(name="option[]")と配列として受け取れる環境もあります。その場合はJavaScript側もfd.getAll("option[]")と、[]を含めた名前で取得します(この[]付きの形は今回は未実行です)。
未チェックのcheckboxは送信されない
どちらの結果にもagreeがありません。チェックの入っていないcheckboxは、名前ごと送信されないのがHTMLの決まりです。「agree=off」のような値が届くわけではありません。
そのため、サーバー側で「届いた項目だけを更新する」という作りにしていると、チェックを外しても保存済みの値がオンのまま残る、ということが起こります。対処は3通りあります。
| 対処 | やり方 | 向いている場面 |
|---|---|---|
| hiddenを前に置く | 同じnameのhiddenをcheckboxより前に書く |
JavaScriptなしの通常送信 |
| サーバーで補う | 項目が届かなければオフとして扱う | サーバー側を変更できるとき |
| JavaScriptで補う | fd.has("agree")でtrue / falseにする |
fetchで送るとき |
hiddenを前に置く方法
完成形のフォームのmailがこの形です。
<input type="hidden" name="mail" value="0">
<label><input type="checkbox" name="mail" value="1"> お知らせメールを受け取る</label>
未チェックならmail=0だけ、チェックありならmail=0&mail=1が届きます。
getAll(mail)=["0","1"] 最後=1
サーバー側で同じ名前の最後の値を採用すれば、未チェックは0、チェックありは1になります。同じ名前が重なったときにどれを採用するかは、サーバー側の言語やフレームワークによって異なるため、使う環境の受け取り方を一度確かめてから取り入れてください。JavaScriptで読むならfd.getAll("mail").at(-1)で最後の値を取れます。
JavaScriptで補う方法
fetchでJSONを送るなら、hasで真偽値に直すのが簡潔です。
form.addEventListener("submit", async (e) => {
e.preventDefault();
const fd = new FormData(form);
const body = {
size: fd.get("size"),
tags: fd.getAll("tags"),
color: fd.get("color"),
option: fd.getAll("option"),
agree: fd.has("agree"),
};
await fetch("/api/order", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
});
(このfetchの送信先/api/orderは例で、今回は未実行です。)
valueを省略するとonが送られる
agreeにはvalueを書いていません。チェックを入れてFormDataを見ると、次のようになります。
agree=on
checkboxとradioは、valueを省略すると文字列onが値になります。 1個だけのcheckboxなら「届いたらオン」と判定できるので困りませんが、同じnameで複数並べたときにvalueを忘れると、どれを選んでもonになり、区別がつかなくなります。複数並べるときは必ずvalueを書きましょう。
細かい挙動をまとめて確認
送信まわりで迷いやすい形を1つのフォームに詰めて、FormDataの内容を確かめました。
<form id="f">
<select name="a"><option>りんご</option><option value="b">バナナ</option></select>
<select name="none" multiple><option value="1">1</option></select>
<select name="dis">
<option value="x" disabled selected>選んでください</option>
<option value="y">Y</option>
</select>
<select name="two">
<option value="1" selected>1</option>
<option value="2" selected>2</option>
</select>
<input type="radio" name="r" value="1"><input type="radio" name="r" value="2">
<input type="radio" name="rr" value="1" checked><input type="radio" name="rr" value="2" checked>
<input type="checkbox" name="c1" checked>
<input type="checkbox" name="c2" value="" checked>
<input type="checkbox" name="c3" value="yes" checked disabled>
<input type="checkbox" checked value="noname">
<input type="radio" name="r2" checked>
</form>
a="りんご"
two="2"
rr="2"
c1="on"
c2=""
r2="on"
r.value=""
has(r)=false
has(none)=false
has(dis)=false dis.value="x"
| 書き方 | 結果 | 覚えておくこと |
|---|---|---|
optionにvalueなし(a) |
表示テキスト「りんご」が届く | 表示を変えると値も変わる。valueを書くと安定する |
select multipleで未選択(none) |
送信されない | checkboxと同じく名前ごと届かない |
disabledのoptionが選択中(dis) |
送信されない | select.valueはxを返すが、送信内容には入らない |
単一selectでselectedが2つ(two) |
あとのほうが選ばれる | selectedは1つにする |
radioが未選択(r) |
送信されない | 必須ならrequiredか初期値を付ける |
radioでcheckedが2つ(rr) |
あとのほうが選ばれる | checkedは1つにする |
checkboxでvalueなし(c1) |
on |
複数並べるならvalueを書く |
checkboxでvalue=""(c2) |
空文字が届く | 省略と空文字は別の扱い |
disabledのcheckbox(c3) |
送信されない | 見せるだけで値も送りたいならhiddenを併用 |
nameなし |
送信されない | nameは必ず書く |
必須にするrequiredの挙動
3つの部品にrequiredを付け、未入力のまま検証の状態を調べました。
<form id="f">
<input type="checkbox" name="agree" required>
<input type="radio" name="r" value="1" required>
<input type="radio" name="r" value="2">
<select name="s" required>
<option value="">選んでください</option>
<option value="1">1</option>
</select>
</form>
for (const e of document.querySelector("#f").elements) {
console.log(e.name + "(" + e.type + ") valueMissing=" + e.validity.valueMissing
+ " / " + e.validationMessage);
}
agree(checkbox) valueMissing=true / Please check this box if you want to proceed.
r(radio) valueMissing=true / Please select one of these options.
r(radio) valueMissing=true / Please select one of these options.
s(select-one) valueMissing=true / Please select an item in the list.
メッセージが英語なのは、検証に使ったChromiumの表示言語が英語のためで、日本語環境では日本語の文面になります。
| 部品 | requiredの意味 | 注意点 |
|---|---|---|
| checkbox | その1個にチェックが必要 | 「複数のうち1つ以上」は表現できない。JavaScriptで数を数える |
| radio | グループのどれか1つが選ばれていればよい | 1個に付ければグループ全体に効く(上の結果で2個目もvalueMissing=true) |
| select | 選ばれたoptionの値が空文字でないこと |
案内用の先頭optionはvalue=""にする |
checkboxのグループで「1つ以上選ぶ」を必須にしたいときは、送信時に数を調べます。
form.addEventListener("submit", (e) => {
const first = form.querySelector('input[name="option"]');
const n = form.querySelectorAll('input[name="option"]:checked').length;
first.setCustomValidity(n === 0 ? "1つ以上選んでください" : "");
if (!form.reportValidity()) e.preventDefault();
});
(このコードは今回は未実行です。setCustomValidityに空文字以外を渡すと、その部品が検証エラーの扱いになります。)
つまずきやすい点と直し方
| 症状 | 原因 | 直し方 |
|---|---|---|
| チェックを外しても保存値が変わらない | 未チェックのcheckboxは送信されない | hiddenを前に置く、またはサーバーやfd.hasで補う |
どれを選んでもonが届く |
valueを書いていない |
選択肢ごとにvalueを書く |
| radioが2つ同時に選べる | nameがそろっていない |
同じグループは同じnameにする |
| 複数選択なのに1つしか取れない | getやselect.value、Object.fromEntriesを使っている |
getAllやselectedOptionsを使う |
| 何も送信されない | nameがない、またはdisabled |
nameを書く。値も送りたいならhiddenを併用 |
| JavaScriptで値を変えたのに連動しない | 代入ではchangeが発生しない |
dispatchEvent(new Event("change", { bubbles: true })) |
| 初期値を入れたのに空になる | selectに存在しない値を代入した | selectedIndexが-1でないか確かめる |
[checked]で今の状態が取れない |
属性は初期値を表す | :checkedまたはcheckedプロパティを使う |
| 文字をクリックしても反応しない | labelと結び付いていない |
labelで包む、またはforとidをそろえる |
| 戻るボタンで前の選択が残る | ブラウザーが入力を復元している | 困る場合はautocomplete="off"を検討(今回は未実行) |
よくある質問
Q. selectの初期値を「選んでください」にするには?
A. 先頭にvalue=""のoptionを置きます。selectedを書かなければ先頭が初期値になります。selectにrequiredを付けると、案内のまま送信しようとしたときにブラウザーが止めてくれます。
Q. checkboxの値をtrue / falseで受け取りたいときは?
A. JavaScriptならinput.checked、FormDataならfd.has("名前")が真偽値を返します。通常の送信では未チェックの項目が届かないので、同じ名前のhiddenを前に置くか、サーバー側で「届かなければオフ」と扱います。
Q. radioの選択を外して未選択に戻せますか?
A. 利用者の操作では戻せません。JavaScriptでinput.checked = falseとするか、form.reset()で初期状態に戻します。選ばないことも答えになる場合は、「指定なし」の選択肢を用意すると伝わりやすくなります。
Q. select multipleとcheckboxはどちらを使えばよいですか?
A. 送信される形はどちらも同じ(同じ名前の繰り返し)で、getAllで配列として取れます。選択肢が少ないなら、状態がひと目でわかるcheckboxが向いています。
まとめ
- 初期値はselectが
selected、checkboxとradioがchecked。 属性は初期値、プロパティは今の状態を表す - 値の取得は、selectとradioが
value、checkboxがchecked。 フォーム全体ならFormDataが手早い - 複数選択は
getAllで取る。get、select.value、Object.fromEntriesは1つしか返さない - 未チェックのcheckboxは名前ごと送信されない。
hiddenを前に置くか、fd.hasやサーバー側で補う valueを省略したcheckboxとradioはonが送られる。 複数並べるときは必ずvalueを書く- 変更は
changeで受け取る。 JavaScriptからの代入では発生しないので、必要ならdispatchEventで送る labelとfieldset・legendで、押しやすく伝わりやすいフォームになる
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「HTML select・checkbox・radioの書き方|初期値と値取得」
株式会社RJCでは、HTMLフォームの基本とJavaScriptでの扱い方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。