JavaScript フォームとフォームコントロールの使い方

以下は JavaScript を使ったフォームの作成方法やフォームコントロールの使い方についての覚書です。

Form オブジェクトを使った要素へのアクセスやそのプロパティ、コントロール(ボタンやテキストフィールド、テキストエリア、チェックボックス、ラジオボタン、セレクトボックス)の基本的な使い方やイベント処理などについてサンプルを交えて解説しています。

関連ページ:

作成日:2021年8月4日

フォーム

フォームやその部品(フォームコントロール)を使うとユーザーが入力したり選択した値をサーバーに送信したり、それらの値を JavaScript を使って何らかの処理をすることができます。

以下はテキストフィールドと送信及びリセットボタンのフォームコントロールで構成されたフォームです。

送信ボタンをクリックするか、テキストフィールドにカーソルを置いて return キーを押すとフォームはサーバーに送信され、PHP の処理により入力された値が正しいメールアドレスの形式であれば、フォームの下に入力された文字が出力され表示されます。

以下は上記フォームのコードです。PHP を記述してあるのでファイルの拡張子は .php になっています。

form-sample-01.php
<form name="myForm" method="post">
  <div>
    <label for="email">メールアドレス: </label>
    <input name="email" id="email" value="" size="20">
  </div>
  <input type="submit" name="send">
  <input type="reset" name="clear" value="クリア">
</form>

<?php
  $email = filter_input( INPUT_POST, 'email', FILTER_VALIDATE_EMAIL );
  $message = $email ? '入力したメールアドレス:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') : '';
?>
<p><?php echo $message; ?> </p>

HTML

form 要素の action 属性を省略して method 属性に post を指定しているので、このフォームは POST メソッドで自分自身に送信されます。

4行目の input 要素は type 属性を省略しているので type="text" が適用されてテキストフィールドになります。

input 要素の type 属性に submit を指定するとそのフォームの送信ボタンになり、reset を指定するとそのフォームのリセットボタンになります。value 属性を指定するとボタンに表示する文字(デフォルトの「送信」や「リセット」)を変更することができます。

関連ページ: HTML フォームの設置

PHP

POST メソッドの場合、$_POST[ '変数名' ] で送信されたフォーム部品の値を取得することができます。変数名にはフォーム部品の name 属性の値を指定します。この例の場合、 $_POST['email'] でテキストフィールドに入力された値を受け取ることができます。

上記の例では filter_input() という PHP 関数を使って入力された値が正しいメールアドレスの形式の場合のみ変数 $email に値を格納し、未入力や形式が正しくない場合は $email には false が代入されます。filter_input() の第2パラメータには取得する変数の名前(name 属性の値)を指定しています。

また、変数 $email には filter_input() により正しい形式のメールアドレスが格納されますが、ユーザーのデータをブラウザに出力する際は、原則として全てのデータを出力時に htmlspecialchars() でエスケープ処理します。

PHP を使ったフォームの操作や検証などについては以下を御覧ください。

関連ページ:PHP フォーム

JavaScript を追加

以下は JavaScript を使って、送信ボタンをクリックした際にテキストフィールドに入力された値を確認して何も入力されていない場合はアラートを表示して送信を中止する例です。

入力された値が空の場合は送信しないようにするには、HTML5 のフォームの検証機能の required 属性を使うこともできます(詳細:JavaScript フォームの検証)。

この例ではフォーム要素の取得に document.forms を使っていますが、querySelector() などの DOM のメソッドを使うこともできます。

また、以下では DOMContentLoaded イベントを使って DOM ツリーの構築(解析)が完了した時点で実行するようにしていますが、</body> の直前で JavaScript を記述したり読み込む場合は省略しても大丈夫な場合が多いです(JavaScript の記述位置)。

form-sample-02.php
<form name="myForm" method="post">
  <div>
    <label for="email">メールアドレス: </label>
    <input name="email" id="email" value="" size="20">
  </div>
  <input type="submit" name="send">
  <input type="reset" name="clear" value="クリア">
</form>
<?php
  $email = filter_input( INPUT_POST, 'email', FILTER_VALIDATE_EMAIL );
  $message = $email ? '入力したメールアドレス:' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') : '';
?>
<p class="output"><?php echo $message; ?> </p>

<script>
//DOM ツリーが構築されたら実行するように DOMContentLoaded イベントにリスナーを登録
document.addEventListener('DOMContentLoaded', () => {

  //フォーム要素を取得
  const myform = document.forms.myForm;
  //ユーザー名を入力する name 属性の値が email の input 要素を取得
  const email = myform.email;

  //フォームに submit イベントのイベントリスナーを登録
  myForm.addEventListener('submit', (e) => {
    //テキストフィールドの値が空の場合
    if(email.value == '') {
      alert('メールアドレスをご入力ください。');
      //デフォルトの動作(送信)を中止
      e.preventDefault();
    }
  });
});
</script>

複数のフォーム

同じページに複数のフォームを配置する場合、それぞれの form 要素に一意の(重複しない) name 属性や id 属性を指定します。

このページの例では、form 要素の name 属性は同じ値(myForm)になっていますが、同じページに複数のフォームを配置する場合は form 要素に異なる name 属性の値を指定します。

フォーム部品だけを利用

form 要素を使わずに、フォーム部品(フォームコントロール)だけを利用することもできます。

以下はラジオボタンを選択すると、その value 属性の値を id="foo" の div 要素の背景色に設定する例です(詳細:ラジオボタン)。

フォームサンプル
グレー
<div id="foo">フォームサンプル</div>
<div>
  <input type="radio" name="color" value="blue">青
  <input type="radio" name="color" value="green">緑
  <input type="radio" name="color" value="red">赤
  <input type="radio" name="color" value="#666">グレー
</div>

<script>
  window.addEventListener('DOMContentLoaded', () => {

    //id が foo の div 要素を取得
    const foo = document.getElementById('foo');

    //それぞれのラジオボタンにイベントリスナーを設定
    document.getElementsByName('color').forEach( elem => {
      elem.addEventListener('change', e => {
        //div 要素の背景色を選択されたラジオボタンの値に
        foo.style.setProperty('background-color', e.target.value);
      });
    });
  });
</script>

ボタン

フォームを送信したり、ボタンをクリックしたら何らかの処理を行う場合にボタンを配置しますが、ボタンを表示するには button 要素か input 要素を使用することができ、そのボタンの機能は type 属性で指定します。

フォーム(form 要素)内に配置されたボタンは、そのフォームと関連付けされ、例えば type="submit" のボタンをクリックすればそのフォームが送信され、type="reset" のボタンをクリックすればそのフォームがクリア(リセット)されます。

type="button" のボタンはフォーム内に配置されていても汎用ボタンなので、クリックしてもフォームが送信されたりリセットされることはありませんが、JavaScript を使ってクリックイベントを設定して何らかの処理を実行することができます。

button 要素を使ったボタン

以下は button 要素を使った送信ボタン(type="submit")の例です。ボタンに表示する文字は <button>〜</button> に記述します。

<button type="submit" name="send" value="send1">送信</button>

button 要素の type 属性の初期値は submit なので、フォーム内で送信ボタンとする場合は type 属性を省略できます。

※ 但し、逆に言うとフォーム内で type 属性を指定していない場合や type 属性が空であったり不正な値であったりした場合は送信ボタンとなります。以下の場合、両方とも送信ボタンとして機能してしまいます。

<form name="myForm" action="">
  <input type="email" name="email" value="" size="30">
  <button name="send">送信</button>
  <button name="clear">リセット</button><!-- type 属性を指定していないので送信ボタン -->
</form>

button 要素を使うと表示する文字と value 属性に異なる値を設定できたり、スタイルが設定しやすいなど input 要素のボタンに比べると使いやすいとされています。

button 要素
type 属性 説明
submit 所属するフォームの入力内容をプログラム(サーバー)に送信する送信ボタンを生成します。type 属性を指定していない場合の既定値です。
reset リセットボタンを生成します。このボタンを押すとそのフォームの入力内容の全てをリセット(コントロールを初期値に初期化)します。
button 汎用ボタンを生成します。ボタンには既定の動作がなく押されても何も行いません。クライアント側スクリプトでイベントを設定することができます。

input 要素を使ったボタン

以下は input 要素を使った送信ボタン(type="submit")の例です。ボタンに表示する文字は value 属性に指定します。

<!-- type="submit" で value 属性を省略するとボタンには既定のラベル「送信」が表示されます -->
<input type="submit" name="send">

<!-- 以下はボタンに「クリックで送信」と表示されます -->
<input type="submit" name="send" value="クリックで送信">

input 要素の type 属性の既定値は text なので type 属性を省略するとテキストフィールドになります。

input 要素
type 属性 説明
submit そのフォームの入力内容をプログラムに送信する送信ボタンを生成します。value 属性を省略すると既定のラベル(送信)が表示されます。
reset リセットボタンを生成します。このボタンを押すとそのフォームの入力内容の全てをリセットします。value 属性を省略すると既定のラベル(リセット)が表示されます。
button 汎用ボタンを生成します。表示する文字は value 属性に指定します。ボタンには既定の動作がなく押されても何も行いません。クライアント側スクリプトでイベントを設定することができます。
image テキストではなく画像の送信ボタンを作成するために使用します。value 属性を設定できず、表示する画像へのパスを src 属性で指定します。また、name 属性を指定しても document.forms.elements には含まれないため、id 属性などを指定してアクセスする必要があります。(参考:stackoverflow.com

以下は type="image" の画像を使った送信ボタンにクリックイベントを設定する例ですが、type="image" の input 要素は特別で、document.forms.elements でアクセスしようとするとエラーになります。

<form name="myForm">
  <input type="text" name="myText">
  <input type="image" id="send" name="send" src="btn.png" alt="送信" width="50" height="30">
</form>

<script>
//ボタンの要素に document.forms.myForm.send でアクセスできない(★以下のエラー)
//Uncaught TypeError: Cannot read property 'addEventListener' of undefined
document.forms.myForm.send.addEventListener('click',() => {
  alert('Hello!');
});

//getElementById('send') でアクセスすれば問題なし
document.getElementById('send').addEventListener('click',() => {
  alert('Hello!');
});
</script>

button 要素に背景画像を設定すれば、画像の送信ボタンを作成することができ、他のフォームコントロール同様、document.forms.elements に含まれます。

<style>
button#btn {
  background-image: url("images/btn.png");
  width: 50px;
  height: 30px;
  border: none;
}
</style>

<form name="myForm">
  <input type="text" name="myText">
  <button name="send" id="btn"></button>
</form>

<script>
document.forms.myForm.send.addEventListener('click',() => {
  alert('Hello!');
});
</script>

name 属性での注意

ハイフンは使わない方が無難

HTML では name 属性の値にハイフンを使用することはできますが、スクリプト上で直接ハイフンを記述すると、マイナス記号として解釈されるのでフォーム要素やフォームコントロールの name 属性にはハイフンを使わない方が無難です。

例えば、以下のように form 要素の name 属性にハイフンを使った場合、document.forms のプロパティとしてフォームの name 属性の値でアクセスしようとすると7行目の「my-form」は「my」「-」「form」と解釈され、エラーになります。

<form name="my-form" method="post">
   ・・・中略・・・
</form>

<script>
  //フォーム要素を取得しようとするがエラーになる
  const myform = document.forms.my-form;
  //エラー:Uncaught ReferenceError: form is not defined
  //document.forms.my と - と form
</script>

以下のようにブラケット構文や HTMLCollection の namedItem() メソッド、または querySelector() などを使えばアクセスできますが、ハイフンはドット記法のプロパティでは使えないので可能であれば使わないほうが無難だと思います。

<form name="my-form" method="post">
   ・・・中略・・・
</form>

<script>
//ブラケット構文を使う
const myform = document.forms['my-form'];
//namedItem() メソッドを使う
//const myform = document.forms.namedItem("my-form");
//querySelector() でアクセス
//const myform = document.querySelector('[name="my-form"]');
//getElementsByNamer() でアクセス
//const myform = document.getElementsByName("my-form")[0];
</script>

name 属性や id 属性の値に submit や reset などのメソッド名を使わない

フォームコントロール (送信ボタンやリセットボタン等)の name 属性か id 属性の値に "submit" または "reset" が指定されている場合、フォームの submit() メソッドや reset() メソッドが機能しなくなる場合があります。

以下は MDN/HTMLFormElement.submit からの抜粋です。

もしフォームコントロール (送信ボタン等) の name 属性か id 属性の属性値に "submit" が設定されていた場合、フォームの submit メソッドはマスキングされてしまいます。

以下の場合、ボタンをクリックすると7行目のボタン要素(document.myForm.submit)のイベントの登録は問題ありませんが、11行目の document.myForm.submit() が「 document.myForm.submit は関数ではありません」というエラーになります。

<form name="myForm">
  <input type="text" name="myText">
  <button name="submit" type="button">送信</button>
</form>

<script>
document.myForm.submit.addEventListener('click', () => {
  alert(document.myForm.myText.value);
  //submit() メソッドで送信しようとするが以下のエラーになります
  //Uncaught TypeError: document.myForm.submit is not a function
  document.myForm.submit();  //送信できない
});
</script>

上記の場合、name 属性によるフォームのプロパティ document.myForm.submit は取得できますが、これと同じ名前のメソッド document.myForm.submit() は機能しません。

上記コードの submit の部分を全て reset に入れ替えても同じ現象(エラー)になってしまいます。

※1 但し、上記コードのボタンの type="button" を削除するか、type="submit" に変更した場合、エラーにはならずフォームは送信されますが、これは11行目の submit() メソッドによる送信ではなく、送信ボタンをクリックすることによる送信機能になります。

※2 上記コードの場合、テキストフィールドにフォーカスして return キーを押せばフォームは送信されてしまいます。

以下のようにボタン要素に id を付与して document.getElementById() で取得しても内部的には document.myForm.submit というプロパティが作成されているので同じくエラーになります。name="submit" を削除すれば機能します。

<form name="myForm">
  <input type="text" name="myText">
  <button id="btn" name="submit" type="button">送信</button>
</form>

<script>
// id で要素を取得
document.getElementById('btn').addEventListener('click', () => {
  alert(document.myForm.myText.value);
  //Uncaught TypeError: document.myForm.submit is not a function
  document.myForm.submit();  //送信できない
});
</script>

プロパティ(属性)名を使っても問題が発生する可能性があります。

MDN 要素の名前付けの問題

メソッド名やプロパティ名だけでなく、イベント名や関数名と同じ名前を name 属性や id 属性の値に指定すると混乱しやすいので避けた方が良いかと思います。

同様に、変数名にもメソッドやプロパティ名、イベント名と同じ名前を使わない方が無難かも知れません。

name="name"

名前を入力するテキストフィールドの name 属性の値に「name」を指定することは良くあり通常は問題ありませんが、フォームコントロールの form プロパティを使ってそのコントロールの所属する form 要素を参照してその name 属性の値を取得しようとすると期待通りにはなりません(このような使い方をすることはあまりないと思うので気にしなくても大丈夫ですが)。

以下では name 属性の値が name の要素を取得して変数 myInput に代入して、myInput.form でその所属する form 要素の属性を出力しています。

myInput.form.name では所属する form 要素の name 属性の値(myForm)が取得できそうですが、実際には myInput.form の name プロパティ、つまり form 要素(myInput.form)内の「name 属性の値が name の要素」を取得します。

フォーム内のコントロールに name 属性を設定すると、そのフォームのプロパティとして(その値のプロパティが)生成されます。この場合、getAttribute() を使えば form 要素の name 属性を取得できます

<form name="myForm" method="post">
  <input type="text" name="name" size="35">
  <button type="submit" name="send">Submit</button>
</form>

<script>
  //name 属性の値が name の要素
  const myInput = document.querySelector('input[name="name"]') ;
  //form プロパティでその要素のフォームを参照しその method 属性の値を出力
  console.log(myInput.form.method);  //post
  //同様にフォームの name 属性の値を出力しようとするが「name 属性の値が name の要素」を参照
  console.log(myInput.form.name);  //<input type="text" name="name" size="35">
  //myInput と myInput.form.name が同一であれば Equal と出力
  if(myInput === myInput.form.name) console.log('Equal'); //Equal
  //getAttribute() を使えば name 属性を取得できる
  console.log(myInput.form.getAttribute('name'));  //myForm
</script>

JavaScript の記述位置

JavaScript を <head> 内に記述するなど、操作対象の HTML の前に記述する場合などでは、DOM ツリーの構築(解析)が完了した時点で処理を実行するように、DOMContentLoaded などのイベントを使って処理を記述する必要があります。

<head>
<script>
//DOM ツリーが構築されたら実行 ※画像やスタイルシートの読み込み前
document.addEventListener('DOMContentLoaded', function(){
  document.getElementById('sample').style.setProperty('color', 'blue');
});
</script>
</head>
<body>
  <p id="sample">Sample</p>
</body>

load イベントは、画像やスタイルシートなどを含むページ全体が読み込まれたときに実行する必要がある場合に使用します。

JavaScript の記述や読み込みは body の閉じタグ </body> の直前に記述すれば、ほとんどの場合は問題ないと思いますが、但しその時点で DOM のレンダリングの完了が保証されているわけではないので、処理内容や必要に応じて DOMContentLoaded などの DOM を操作する際に利用できるイベントを使って処理を記述します(関連項目:実行タイミング)。

※ 以降では DOMContentLoaded イベント登録の記述はしていないので必要に応じて追加します。

イベントリスナー

イベントの設定方法には以下のようなものがあります。

addEventListener() を使う方法は、IE9 未満には対応していませんが、同じ要素に複数のイベントハンドラーを登録できるなどのメリットがあるので、以降では主に addEventListener() を使ってイベントを設定しています。

以下は onclick ハンドラーを使ってボタンをクリックしたらアラートを表示する例です。

13行目のイベントハンドラ関数の設定では関数そのもの(関数名の後に括弧を付けない)を指定します。sayHello() と括弧を付けてしまうと関数を呼び出した結果を代入することになってしまいます。

<input type="button" id="hello" value="Click Here">

<script>
//ボタンの要素(input 要素)
const hello_btn = document.getElementById("hello");

//イベントハンドラの関数の定義
function sayHello() {
  alert("Hello");
};

//ボタンの要素の onclick 属性にイベントハンドラの関数を設定
hello_btn.onclick = sayHello;

// 関数を別途定義せず無名関数を使って設定する場合
/*
hello_btn.onclick = function(){
  alert('Hello');
};
*/
</script> 

以下はボタンをクリックすると、表示されているカウントを増やしていく例で addEventListener() を使って設定しています。

ボタン要素に click イベントのリスナー関数を addEventListener() を使って登録しています。

<button id="btn">Count Up : <span>0</span></button>

<script>
  //イベントを登録するボタン要素
  const btn = document.getElementById("btn");
  //カウントを表示する span 要素
  const count_out = btn.getElementsByTagName('span')[0];
  //カウント
  let count = 0;

  //イベントが発生したときに呼び出されるリスナー関数
  const countUp = () => {
    count++;
    count_out.textContent = count;
  };

  //ボタン要素に click イベントのリスナーを登録
  btn.addEventListener('click', countUp);
</script> 

上記の例ではリスナー関数を別途定義していますが、以下のように無名関数を使うこともできます。

//イベントを登録するボタン要素
const btn = document.getElementById("btn");
//カウントを表示するを span 要素
const count_out = btn.getElementsByTagName('span')[0];
//カウント
let count = 0;

//ボタン要素に click イベントのリスナーを無名関数を使って登録
btn.addEventListener('click', () => {
  count++;
  count_out.textContent = count;
});

以降の例では無名関数を使うことが多いですが、無名関数を使って登録するとリスナー関数に名前がないため removeEventListener() を使ってイベントリスナーを削除することができなかったり、ループで関数を呼び出す際に繰り返しが多くなると効率的ではなくなるなどのデメリットもあります。

アロー関数

アロー関数と function() を使った関数定義では this の参照先が異なるため、addEventListener() のリスナー関数の定義でアロー関数を使う場合は、this の代わりに Event オブジェクトのプロパティ(currentTargettarget)を使います。

以下は input 要素の値(テキストフィールドに入力された値)が変化するたびに input イベントを使って値を span 要素に出力する例です。

出力:

<input type="text" id="textInput" size="40">
<p>出力:<span id="textOut"></span></p>

<script>
  //テキストフィールドの id 属性が textInput を取得(input 要素)
  const textInput = document.getElementById('textInput');
  //id 属性が textOut の span 要素を取得(出力先)
  const textOut = document.getElementById('textOut');

  //テキストフィールドに input イベントを登録
  textInput.addEventListener('input', (e) => {
    //出力先の textContent にイベントが発生している要素(e.currentTarget)の値を設定
    textOut.textContent = e.currentTarget.value;
    //または textOut.textContent = e.target.value; でもこの例の場合は同じ
  });
</script>

以下のように記述すると、textInput を this で参照できない(this は外側のスコープを探索する)ため何も出力されません。

textInput.addEventListener('input', () => {
  //textInput を this で参照できないため何も出力され
  textOut.textContent = this.value;  //NG
});

アロー関数の代わりに function() を使えば、this キーワードはリスナが登録されたオブジェクトを参照するので同様の結果を得られます。

textInput.addEventListener('input', function() {
  textOut.textContent = this.value; //OK
});

関連項目:

Form オブジェクト

Document オブジェクトにはドキュメントに現れるフォームや画像、リンクなどのオブジェクトの配列を値として持つプロパティがあり、その中の1つ forms プロパティにはそのドキュメント内の各フォーム要素に対応するオブジェクト(Form オブジェクト)が格納されています。

JavaScript では Form オブジェクトを使ってフォームの操作(処理)を行うことができます。

window オブジェクト (現在のウィンドウ) プロパティ self, window オブジェクト 自身を参照 navigator オブジェクト location オブジェクト document オブジェクト history オブジェクト screen オブジェクト DOM (Document Object Model) プロパティ forms プロパティ forms[ ] images プロパティ images[ ] anchors プロパティ anchors[ ] links プロパティ links[ ] document.forms Form オブジェクトの集まり 各 Form オブジェクトは elements や name などのプロパティを持ちます

例えば、そのページ(ドキュメント)の最初のフォーム要素には、document.forms[0](document オブジェクトの forms プロパティのインデックス 0 の要素)でアクセスすることができます。

通常の要素のように、フォームやフォームコントロールの要素には getElementByIdquerySelectorAll などの DOM のメソッドを使ってアクセスできますが、Document の forms プロパティ(document.forms)を使うと簡単にアクセスすることができます。

document.forms

document.forms はそのページ(ドキュメント内)の全てのフォーム要素に対応するオブジェクトが格納されている配列のようなオブジェクト(HTMLCollection)です。

document.forms に含まれるそれぞれの要素は、単一の form 要素を表す Form オブジェクト(HTMLFormElement)です。

Form オブジェクトへのアクセス

document.forms を使って Form オブジェクトにアクセスする方法はいろいろあります。以下のようなフォームがある場合、

<form name="myForm">
  <input type="text" name="inputText">
  <input type="submit" name="send">
</form>

form 要素に対応する Form オブジェクト(HTMLFormElement)には以下の方法でアクセスすることができます。

document.forms[0] //フォームのドキュメント中の順序(インデックス番号)で参照
document.forms["myForm"] //配列の添字に name 属性を指定して参照(ブラケット構文)
document.forms.myForm //プロパティとしてフォームの name 属性でアクセス(ドット記法)
document.forms.namedItem("myForm") //HTMLCollection の namedItem メソッド

上記1行目の document.forms[0] は、そのフォームがドキュメント中の最初(インデックス番号が0)のフォームである場合です。同じページ内にフォームが複数あったり、追加や削除を行うと出現順であるインデックス番号の値が変わる可能性があります。

また、form 要素に name 属性を指定した場合は、ドキュメントオブジェクト自身に name 属性で指定した名前のプロパティができ、対応する Form オブジェクトが格納されるため、以下のように .forms なしで記述しても Form オブジェクト(form 要素)にアクセスすることができます。

document.myForm  //一番短い記述

まとめると、以下のような name 属性が設定されたフォームの場合、

<form name="myForm">
  ・・・フォームコントロール・・・
</form>

以下の書式で name 属性が設定された form 要素にアクセスすることができます。

書式と例(name 属性が myForm の場合) 説明
document.forms[インデックス番号]
document.forms[0]
配列のインデックス番号で参照。インデックス番号は0から始まるドキュメント中のそのフォームの出現順(整数)
document.forms['name属性の値']
document.forms['myForm']
配列の添字に name 属性の値を指定して参照(ブラケット構文)
document.forms.name属性の値
document.forms.myForm
Form オブジェクトのプロパティ名(name属性の値)でアクセス(ドット記法)
document.name属性の値
document.myForm
ドキュメントオブジェクトのプロパティ名(name属性の値)でアクセス(上記の .forms を省略した書式)
document.forms.namedItem('name属性の値')
document.forms.namedItem('myForm')
HTMLCollection のメソッド namedItem() でアクセス(.forms は省略可能)

id 属性

id 属性が設定されていれば、name 属性の代わりに id 属性の値を指定することもできます。但し、name 属性のように「document.id属性の値」ではアクセスできません。

<form id="myForm">
  ・・・中略・・・
</form>

<script>
//以下で上記の id="myForm"の form 要素にアクセス可能
document.forms.myForm
document.forms['myForm']
document.getElementById('myForm')

//name 属性と異なり、以下ではアクセスできない
document.myForm   //undefined
</script>

実際には id 属性を指定した要素には単に「id 属性の値」(この例では myForm)だけでアクセスできてしまいますが、この方法は非推奨です(id 属性)。

DOM メソッドでアクセス

以下は querySelector() を使って name 属性の値が myForm の form 要素にアクセスする例です。

document.querySelector('form[name="myForm"]')

Form のプロパティ

以下は Form オブジェクト(HTMLFormElement)の主なプロパティです。

プロパティ 説明
elements 【読み取り専用】そのフォーム内に含まれる全てのフォームコントロールを保持する配列のようなオブジェクト(HTMLCollection
length 【読み取り専用】フォーム内のコントロールの数
name フォームの name 属性の値(フォームの名前)
method フォームの method 属性の値(フォームの送信に使用する HTTP メソッド)
target フォームの target 属性の値(送信して受け取った結果を表示する場所)
action フォームの action 属性の値(送信された情報を処理するプログラムの URI)
encoding | enctype フォームの enctype 属性の値(サーバーへ送信するのに使用するコンテンツの型)
acceptCharset フォームの accept-charset 属性の値(受け付ける文字エンコーディング)
elements(フォームコントロール)

elements プロパティは form 要素内の全てのフォームコントロールが含まれる配列のようなオブジェクトで、elements プロパティを使ってそのフォーム内のフォームコントロールにアクセスできます。

フォームコントロールとは input 要素や select 要素、textarea 要素などのフォームの部品(コントロール要素)のことで以下の要素が該当します。

  • <button>
  • <fieldset>
  • <input> (type="image" は除く。歴史的な経緯から※)
  • <object>
  • <output>
  • <select>
  • <textarea>

※ type="image" の input 要素(画像ボタン)は特別で、elements プロパティには含まれません。

参考:フォームコントロールと見なされる要素

Form オブジェクトへのアクセスと同じように、フォーム内のフォームコントロールにはインデックス番号や name 属性の値、プロパティを使ってアクセスすることができます。

以下のようなフォームがある場合、

<form name="myForm">
  <input type="text" name="inputText">
  <input type="submit" name="send">
</form>

上記フォームの name 属性が inputText の要素には以下のどれでもアクセスすることができます。

Form オブジェクトと elements プロパティを使ってアクセス
//Form オブジェクトに document.forms[0] でアクセスする場合
document.forms[0].elements[0]  //elements[インデックス番号] (最初のコントロール)
document.forms[0].elements['inputText']   //elements["name属性の値"]
document.forms[0]['inputText']   //forms[0] の連想配列
document.forms[0].inputText   //forms[0] のプロパティ

//Form オブジェクトに document.forms['myForm'] でアクセスする場合
document.forms['myForm'].elements[0]
document.forms['myForm'].elements['inputText']
document.forms['myForm']['inputText']
document.forms['myForm'].inputText

//Form オブジェクトに document.forms.myForm でアクセスする場合
document.forms.myForm.elements[0]
document.forms.myForm.elements['inputText']
document.forms.myForm['inputText']
document.forms.myForm.inputText

//Form オブジェクトに document.myForm でアクセスする場合
document.myForm.elements[0]
document.myForm.elements['inputText']
document.myForm['inputText']
document.myForm.inputText 

以下は querySelector() を使って name 属性の値が myForm の form 要素の elements プロパティの最初の要素にアクセスする例です。

document.querySelector('form[name="myForm"]').elements[0]

//上記のフォームの場合、最初の要素は以下でも同じこと(name 属性が inputText の要素)
document.querySelector('form[name="myForm"] input[name="inputText"]')

elements は form 要素内の全てのコントロールが含まれますが、それ以外の要素は含まれません。

例えば、以下のようなフォームの場合、h3 要素や p 要素は elements に含まれません。

<form name="myForm">
  <h3>My Form</h3>
  <p>Please fill out the form below.</p>
  <input type="text" name="name">
  <input type="email" name="email">
  <button type="submit" name="send">送信</button>
  <button type="reset" name="clear">リセット</button>
</form>

Form オブジェクトのプロパティ length にはフォーム内のコントロールの数が格納されています。その値は elements (フォーム内のコントロール)の要素数(elements.length)と同じです。

コントロールの最後の要素のインデックスは length-1 になります。

各要素のプロパティや属性は、その要素にアクセスして要素オブジェクト(Element)のプロパティや属性から取得することができます(関連項目:要素の操作)。

elements は配列のようなオブジェクトHTMLCollection)なので for...of 文が使えます。

//name 属性が myForm の Form オブジェクト
const myForm = document.myForm;
// または const myForm = document.forms.myForm;

// 上記 Form オブジェクトの elements (フォーム内のコントロール)
const myElements = myForm.elements;

//Form オブジェクトのプロパティ length
console.log(myForm.length);  //4

//elements (フォーム内のコントロール)の要素数
console.log(myElements.length);  //4

//elements (フォーム内のコントロール)の最後の要素
console.log(myElements[myElements.length-1].type); //reset
//elements (フォーム内のコントロール)の最後の要素(上記と同じこと)
console.log(myElements[myForm.length-1].type); //reset

//for 文で各コントロールの name 属性の値を出力
for(let i=0; i< myElements.length; i++) {
  console.log(myElements[i].name);
}

//for 文の出力結果
/*
name
email
send
clear
*/

// for of が使えるので以下でも同じ
for (let elem of myElements) {
  console.log(elem.name);
}

同じ値の name 属性

ラジオボタンやチェックボックスのように複数の選択肢を設定する要素では、name 属性に同じ値を設定してそれらを関連付けする必要があります。

そのため、複数の同じ値の name 属性の要素があるラジオボタンやチェックボックスでは elements["name属性の値"] は配列となっているので、name 属性を使ってアクセスする場合は elements["name属性の値"][インデックス] のようにインデックスを使って個々の要素にアクセスします。

但し、1つだけのチェックボックスの場合など、同じ値の name 属性の要素が1つだけの場合は配列にはなっていません。

※正確には配列ではなく、elements プロパティ同様、配列のようなオブジェクト(NodeList )です。

以下の場合、elements['color'] は配列になっています。.color プロパティも同様に配列です。

<form name="myForm">
  <input type="text" name="name">
  <input type="checkbox" name="color" value="blue">青
  <input type="checkbox" name="color" value="green">緑
  <input type="checkbox" name="color" value="yellow">黄
</form>

<script>
  /*以下は最初のチェックボックス要素の value 属性の値を取得しています。*/

  //elements['color'] の最初の要素
  let colorValue = document.myForm.elements['color'][0].value;
  console.log(colorValue);  //blue

  //.color プロパティの最初の要素
  colorValue= document.myForm.color[0].value;
  console.log(colorValue);  //blue

  //.elements プロパティの2番目の要素(1番目はテキストフィールド)
  colorValue = document.myForm.elements[1].value;
  console.log(colorValue);  //blue

  /*以下は全てのチェックボックス要素の value 属性の値を取得して出力しています。*/

  //colors は全てのチェックボックス要素が格納された配列
  const colors = document.myForm.elements.color;
  // 以下と同じこと
  //const colors = document.myForm.elements['color'];

  //配列の要素をループ
  for(let i=0; i<colors.length; i++) {
    //各要素のインデックスと値をコンソールに出力
    console.log( i + ' : ' + colors[i].value);
  }

  /*
  0 : blue
  1 : green
  2 : yellow
  */
</script> 

同じ値の name 属性を設定する

ラジオボタンやチェックボックス以外でも、name 属性に同じ値を設定すれば、elements["name属性の値"] は配列(のようなオブジェクト)になります。

例えば、以下のように複数のメールアドレスを入力するテキストフィールドを作成し、同じ値(この例では emails)の name 属性を設定することができます。

<form name="myForm">
  <div>
    <label for="emails1">E-mail: </label>
    <input type="text" name="emails" id="emails1" size="30">
  </div>
  <div>
    <label for="emails2">E-mail: </label>
    <input type="text" name="emails" id="emails2" size="30">
  </div>
  <div>
    <label for="emails3">E-mail: </label>
    <input type="text" name="emails" id="emails3" size="30">
  </div>
  <input type="button" name="check" value="Check">
  <input type="reset" value="Reset">
</form>

上記の場合、name 属性が emails の全ての要素(配列のようなオブジェクト)は document.myForm.elements.emails または document.myForm.elements['emails'] で取得できます。

以下ではボタンの要素に addEventListener を使ってクリック時のイベントリスナーを登録し、クリックされたら各テキストフィールドのインデックス番号とに入力されている値をコンソールに出力するようにしています。

<script>
  //emails は name 属性が emails の全ての要素が格納された配列
  const emails = document.myForm.elements.emails;
  // または let emails = document.myForm.elements['emails'];

  //name 属性が check の要素(ボタンの要素)
  const checkButton = document.myForm.elements.check;

  //ボタンの要素にクリックイベントを登録
  checkButton.addEventListener('click', function() {
    //配列の要素をループ
    for(let i=0; i<emails.length; i++) {
      //各要素のインデックスと値をコンソールに出力
      console.log( i + ' : ' + emails[i].value);
    }
  })

  //3つのテキストフィールドに値を入力してボタンをクリックした場合の出力例
  /*
  0 : foo@example.com
  1 : bar@example.com
  2 : baz@example.com
   */
</script>

fieldset 要素

フォーム内の複数のコントロールをグループ化する fieldset 要素もフォームコントロールの1つです。

fieldset(HTMLFieldSetElement)では Form オブジェクト同様、elements プロパティを使うことができます。

以下は name 属性の値が require_field の fieldset 要素の elements プロパティを使って name 属性の値が email の input 要素にアクセスしてその属性(size)の値をコンソールに出力しています。

<form name="myForm">
  <fieldset name="require_field">
    <legend>Require Field</legend>
    <div>
    <label for="inputName">Name: </label><br>
      <input type="text" name="inputName" id="inputName" value="" size="20">
    </div>
    <div>
    <label for="email">E-mail: </label><br>
      <input type="email" name="email" id="email" value="" size="30">
    </div>
  </fieldset>
  <div>
    <button type="submit" name="send">Submit</button>
  </div>
</form>

<script>
//name 属性の値が require_field の fieldset 要素
const fieldset = document.myForm.elements.require_field;
//fieldset 要素の elements プロパティで name 属性の値が email の要素にアクセス
console.log(fieldset.elements.email.size);  //30
//form 要素の elements プロパティで name 属性の値が email の要素にアクセス(同じこと)
console.log( document.forms['myForm'].elements.email.size);   //30
//fieldset 要素の form プロパティで所属する form 要素にアクセス
console.log(fieldset.form.name);  //myForm
</script>
fieldset の利用

Form オブジェクトの elements プロパティはそのフォーム内のボタンなどを含む全てのフォームコントロールが含まれています。

そのため、例えば for 文でループして特定の要素の値を取得したい場合などでは、ボタン要素などを除外する必要があります。

fieldset 要素も form 要素と同じように elements プロパティを持っているので、fieldset 要素で特定のコントロールをグループ化することでそのグループだけに対して処理することができます。

または、同じ値の name 属性を設定することでそれらを配列(のようなオブジェクト)として処理することもできます。

以下は3つのテキストフィールドを fieldset 要素でグループ化しています。legend や label 要素はフォームコントロールではないので elements プロパティには含まれません。

<form name="myForm">
  <fieldset name="required_field"><!-- fieldset ここから -->
    <legend>Required Field</legend>
    <div>
      <label for="name2">Name: </label>
      <input type="text" name="name" id="name2" value="" size="30">
    </div>
    <div>
      <label for="email2">E-mail: </label>
      <input type="text" name="email" id="email2" value="" size="30">
    </div>
    <div>
      <label for="tel2">TEL: </label>
      <input type="text" name="tel" id="tel2" value="" size="30">
    </div>
  </fieldset><!-- fieldset ここまで -->
  <button type="button" name="check">Check</button>
  <button type="reset" name="clear">Clear</button>
</form>

fieldset 要素の elements プロパティには、3つのテキストフィールドが入っているので、それをループしてそれぞれの要素の name プロパティと value プロパティを出力しています。

<script>
//name 属性が myForm の form 要素
const myForm = document.myForm;

//フォームのボタンにクリックイベントを登録
myForm.check.addEventListener('click', ()=> {
  //name 属性が myForm の form 要素の fieldset 要素
  const fieldset = myForm.elements.required_field;
  //fieldset 要素の elements プロパティを for 文でループ
  for(let i=0; i<fieldset.elements.length; i++) {
    //elements プロパティの各要素の name プロパティと value プロパティを出力
    console.log(fieldset.elements[i].name + ': ' + fieldset.elements[i].value);
  }
});

//コンソールへの出力例
/*
name: Foo
email: foo@exmaple.com
tel: 123-456-789
*/
</script>

elements は配列のようなオブジェクトHTMLCollection)なので for...of 文が使えるので上記は以下のように記述することができます。

const myForm = document.myForm;

myForm.check.addEventListener('click', ()=> {
  const fieldset = myForm.elements.required_field;
  for (let elem of fieldset.elements) {
    console.log(elem.name + ': ' + elem.value);
  }
});;

フォームを参照

フォームコントロールの form プロパティを使ってそのコントロール要素が所属するフォームを参照することができます。

以下は document.querySelector() で name="inputName" の input 要素を取得して変数 inputName に代入し、input 要素の所属する form 要素を inputName.form で参照しています。

そして form 要素のプロパティ(name 属性や method 属性の値)をコンソールに出力しています。

14行目は input 要素の属する form 要素の send プロパティ(name="send" の input 要素)の value 属性の値を取得しています。

<form name="myForm" action="checkForm.php" method="post">
  <input type="text" name="inputName" size="35">
  <button type="submit" name="send" value="nameSubmit">Submit</button>
</form>

<script>
  //name 属性の値が inputName の要素
  const inputName = document.querySelector('input[name="inputName"]') ;
  //form プロパティでその要素のフォームを参照
  console.log(inputName.form.name);  //myForm
  console.log(inputName.form.action);  //http://example.com/path/checkForm.php
  console.log(inputName.form.method);  //post
  //form の send プロパティ(name="send" の input 要素)の value の値
  console.log(inputName.form.send.value); //nameSubmit
</script>

但し、もし上記の input 要素の name 属性の値を name としてしまうと input 要素の .form.name は form 要素の name 属性の値ではなく、name 属性の値が name の要素(input 要素 = 自分自身)を参照してしまいます。

Form のメソッド

以下は Form オブジェクト(form 要素)の主なメソッドです。

メソッド 説明
reset() フォームを初期状態にリセットします
submit() フォームをサーバーへ送信します。HTML5 の検証は行われず、submit イベントも発生しません。
reportValidity() このフォームのコントロールに設定された HTML5 の検証を満たしていれば true を返し、そうでなければ false を返します。 false が返された場合、キャンセル可能な invalid イベントが無効なコントロールそれぞれについて発行されます。
requestSubmit() フォームをサーバーへ送信します。submit() とは異なり、HTML5 の検証も行われ、submit イベントも発生します。
submit() メソッド

フォームのメソッド submit() を呼びだすことで、手動でサーバにフォームを送信することができます。

但し、ユーザーが送信ボタンをクリックしたり return キーを押してフォームを送信するのと全く同じではなく、例えば submit イベントは発生しません。

また、submit() メソッドを使ってフォームを送信した場合は HTML5 の検証は行われません。

以下は input 要素に required 属性を指定して入力を必須としているので何も入力せず送信しようとすると、HTML5 の機能で「このフィールドを入力してください」などのメッセージが表示され、送信することができないようにしています。

<form name="myForm">
  <input type="text" name="myText" required><!-- required 属性を設定-->
  <button name="send">送信</button><!-- type を省略しているので type="submit" と同じ-->
</form>

しかし、以下のように button に type="button" を指定して通常のボタンにして、click イベントを使って submit() でフォームを送信すると、HTML5 の検証は行われず、何も入力せず送信できてしまいます。また、その際、フォームの submit イベントは発生しません。

クリックで HTML5 の検証が行われない例
<form name="myForm">
  <input type="text" name="myText" required><!-- required 属性を設定-->
  <button name="send" type="button">送信</button>
</form>

<script>
//ボタンに click イベントのイベントリスナーを登録
document.myForm.send.addEventListener('click', () => {
  //submit() でフォームを送信
  document.myForm.submit();
});

//フォームに submit イベントのイベントリスナーを登録
document.myForm.addEventListener('submit', () => {
  alert('submit');
});
</script>

但し、テキストフィールドにカーソルを置いて何も入力しない状態で、return キーを押せば click イベントは発生せずフォームにより送信が実行されるので HTML5 のフォームの検証が行われます。

また、テキストフィールドに値を入力してフォーカス状態にして return キーを押せば click イベントは発生しませんが、submit イベントは発生するのでアラートが表示されます。

submit() メソッドを使ってフォームを送信する際に、HTML5 の検証を行うには reportValidity() を使って検証が満たされているかをチェックしたり、requestSubmit() を使うなどの方法があります。

reportValidity()

form 要素の reportValidity() メソッドを使うとフォームの子要素のコントロールが設定した HTML5 の検証を満たしているかをチェックすることができます。

reportValidity() はコントロールが制約を満たしていれば true を返すので、以下ではコントロールが検証をパスしている場合にのみ submit() でフォームを送信するようにしています。

また、reportValidity() はコントロールが制約を満たしていない場合は false を返し、制約を満たしていない要素で invalid イベントが発行され、ユーザー(ブラウザ)にエラーメッセージを表示します。

そのため、何も入力されていない状態でボタンをクリックすると、「このフィールドを入力してください」などのエラーメッセージが表示されますが、 submit() は実行されずフォームは送信されません。

値が何か入力されていれば検証を満たしているので、ボタンをクリックするとフォームが送信されますが、ボタンのクリックでは submit イベントは発生しないのでアラートは表示されません。

カーソルを入力フィールドに置いて、値が何か入力された状態で return キーを押すと、フォームは送信され submit イベントが発生してアラートが表示されます。

<form name="myForm">
  <input type="text" name="myText" required><!-- required 属性を設定-->
  <button name="send" type="button">送信</button>
</form>

<script>
//ボタンに click イベントのイベントリスナーを登録
document.myForm.send.addEventListener('click', () => {
  //コントロールが検証を満たしていれば submit() でフォームを送信
  if(document.myForm.reportValidity()) {
    document.myForm.submit();
  }
});

//フォームに submit イベントのイベントリスナーを登録
document.myForm.addEventListener('submit', () => {
  alert('submit');
});
</script>

requestSubmit()

requestSubmit() を使うと、送信ボタンをクリックしてフォームを送信するのと同様の送信を行うことができます。

以下の場合、ボタンをクリックすると HTML5 の検証が行われ、submit イベントも発生するのでアラートが表示されます。

<form name="myForm">
  <input type="text" name="myText" required><!-- required 属性を設定-->
  <button name="send" type="button">送信</button>
</form>

<script>
//ボタンに click イベントのイベントリスナーを登録
document.myForm.send.addEventListener('click', () => {
  // requestSubmit() でフォームを送信(送信ボタンのをクリックするのと同じ)
  document.myForm.requestSubmit();
});

//フォームに submit イベントのイベントリスナーを登録
document.myForm.addEventListener('submit', () => {
  alert('submit');
});
</script>

submit() は単にフォームを送信するだけです。 一方、requestSubmit() は、送信ボタンがクリックされたかのように機能し、HTML5 の検証が設定sれていればフォームのコンテンツが検証され、検証が成功した場合にのみフォームが送信されます。 フォームが送信されると、submit イベントが発生します。

submit() の使用例

submit() は例えば、フォームを動的に作成してそのフォームを送信する場合などに使えます。

以下は createElement() メソッドを使ってフォームを作成し、そのフォームを submit() メソッドで action 属性で指定した URL に送信する例です。

ボタンをクリックすると GET メソッドなので ?q=JavaScript のクエリが action 属性で指定した送信先の Google 検索の URL に追加され、「JavaScript」についての Google の検索結果が別ウィンドウで表示されます。

<button id="searchBtn">JavaScript について検索</button>

<script>
  //form 要素を作成
  const searchForm = document.createElement('form');
  //form 要素の action 属性を設定(送信先を Google 検索へ)
  searchForm.action = 'https://google.com/search';
  //form 要素の method 属性に GET を設定(URL に ? 区切りで値を追加して送信)
  searchForm.method = 'GET';
  //form 要素の target 属性(結果を表示する場所)に _blank を設定
  searchForm.target = '_blank';
  //form 要素に送信する input 要素を追加(GET メソッドに q=JavaScript が追加される)
  searchForm.innerHTML = '<input name="q" value="JavaScript">';
  //form 要素を非表示に
  searchForm.style.setProperty('display', 'none');
  //body に生成した form 要素を追加
  document.body.append(searchForm);

  //既存のボタンに click イベントのイベントリスナーを登録
  document.getElementById('searchBtn').addEventListener('click', () => {
    //ボタンをクリックしたら作成したフォームを送信
    searchForm.submit();
  });

</script>

イベント

以下は Form オブジェクト(form 要素)の主なイベントです。

イベント 説明
reset フォームがリセットされたときに発生します。
submit フォームが送信されたときに発生します。

フォームは以下の方法で送信されます。

  • フォームの送信ボタン(type="submit")をクリック
  • フォームの入力欄をクリックして return キーを押す
  • JavaScript でフォームのメソッド submit() または requestSubmit() を呼び出す(※)

※ submit() メソッドを使った送信では submit イベントは発生しません。

以下は addEventListener を使って submit イベントと reset イベントを登録する例です。

フォームが送信される際に発生する submit イベントではテキストフィールドに値が入力されているかをチェックし、入力されていない場合はアラートを表示し、Event オブジェクト(e)の preventDefault() でデフォルトの動作(送信)をキャンセルします。デフォルトの動作を停止しないとフォームは送信されてしまいます。

addEventListener のリスナー関数には Event オブジェクト(この例では e として受け取っています)が引数として渡されます。

リセットボタンをクリックされた際に発生する reset イベントでは、confirm ダイアログを表示してユーザーがキャンセルを選択した場合は、デフォルトの動作のリセットを停止します。

<form name="myForm">
  <input type="text" name="name" value="" size="20">
  <input type="email" name="email" value="" size="30">
  <button type="submit" name="send">送信</button>
  <button type="reset" name="clear">リセット</button>
</form>

<script>
//フォームを取得
const form = document.myForm;

//フォームに submit イベントを登録
form.addEventListener('submit', (e) => {
  //送信時のテキストフィールド(name="name")の値
  const name_val = form.name.value;
  //送信時のテキストフィールド(name="email")の値
  const email_val = form.email.value;
  //値が未入力の場合はアラートを表示してデフォルトの動作の送信を中止
  if(name_val === '' | email_val === ''){
    alert('入力は必須です。');
    e.preventDefault();
  }
});

//フォームに reset イベントを登録
form.addEventListener('reset', (e) => {
  //confirm ダイアログを表示
  const response = confirm('値を全てクリアしますか?');
  if(!response) {
    //キャンセルがクリックされたらデフォルトの動作のリセットを中止
    e.preventDefault();
  }
});
</script>

submit イベントと click イベント

通常のフォームの送信(送信ボタンをクリックしたり、フォームの入力欄をクリックして return キーを押す)では、click イベントと submit イベントの両方が発生します。

click イベント → submit イベントの順で発生します。

以下のフォームを送信すると、ボタンをクリックしても入力欄をクリックして return キーを押しても「click」及び「submit」と2回アラートが表示されます。

<form name="myForm">
 <input type="text" name="textInput" size="30">
  <button type="submit" name="send">送信</button>
  <button type="reset" name="clear">クリア</button>
</form>

<script>
  document.myForm.addEventListener('submit', (e) => {
    alert(e.type); //submit とアラート表示
    e.preventDefault();  //※
  });

  document.myForm.send.addEventListener('click', (e) => {
    alert(e.type); //click とアラート表示
  });

</script> 

(※)この例では実際にフォームが送信されるかどうかは関係がないのと、フォームが送信されるとページの先頭に移動してしまうので、e.preventDefault() でフォームの送信をしないようにしています。

送信時の位置を保持

フォームを送信(submit)すると、 action 属性で指定したファイルが読み込まれ、送信した際の画面の表示位置はリセットされページの先頭が表示されます。

action 属性は指定していない場合は自身のファイルが読み込まれ、ページの先頭に移動します。

以下は submit イベントを使って、フォームの送信先を自分自身にした場合に、送信した際の表示位置を保持してページロード後も同じスクロール位置で表示する例です。

※この場合、PHP が実行できるようにファイルの拡張子を .php にするか、.htaccess ファイルなどを使って拡張子 .html で PHP を実行できるようにする必要があります。

フォームの HTML ではフォームを送信する際の位置の情報(スクロール量)を保存するための type="hidden" を指定した input 要素(隠しフィールド)を用意します。name 属性の値は任意ですが、この例では scroll_top という値を指定しています。

フォームを送信する時点のスクロール量を JavaScript の window.scrollY で取得し、それを隠しフィールド(この例では name 属性が scroll_top の input 要素)の value 属性に設定します。

フォームが送信されていない場合は、PHP の変数 $_REQUEST['scroll_top'] は設定されていないので、value 属性には isset() で判定して、設定されていればその値を、されていれば空文字を設定しています。

フォームが送信されてページが再読み込みされると、PHP の変数 $_REQUEST['scroll_top'] で隠しフィールドに設定したスクロール量が取得できます。この例では GET メソッドと POST メソッドの両方の場合に対応するように、値の取得は「$_REQUEST」スーパーグローバル変数を使用しています。

ページが読み込まれたら、隠しフィールドの値を確認し(値が空でなければ)隠しフィールドの値を使って window.scroll() で元の位置にスクロールします。

この場合、DOM ツリー構築完了後、画像やスタイルシートなどの読み込みが完了したら実行するように DOMContentLoaded ではなく、load イベントを使っています。DOMContentLoaded を使う場合は、window に対して登録すれば良いようです(document に対しての登録では、コンテンツにもよると思いますが、正確なスクロール位置が取得できないようです)。

scroll-myform.php(PHP が使える必要があります)
<form name="myForm" method="post">
  <div>
    <label for="name">名前 </label>
    <input name="name" id="name" value="" size="20">
  </div>
  <button>送信</button>
  <!-- 隠しフィールド(垂直方向のスクロール量を value に設定) -->
  <input type="hidden" name="scroll_top" value="<?php echo isset($_REQUEST['scroll_top']) ? $_REQUEST['scroll_top']: ''; ?>">
</form>

<script>
//load イベントにリスナーを登録
window.addEventListener('load', () => {
  //フォームの submit イベント
  document.myForm.addEventListener('submit', ()=> {
    //name 属性が scroll_top の要素(隠しフィールド)があれば
    if(myForm.scroll_top) {
      //垂直方向のスクロール量を取得
      const scrollTop = window.scrollY ;
      //隠しフィールドの value 属性に現在の垂直方向のスクロール量を設定
      myForm.scroll_top.value = scrollTop;
    }
  });

  //ページが読み込まれて隠しフィールドの値が空でなければ
  if(myForm.scroll_top.value) {
    //隠しフィールドの値を使ってスクロール
    window.scroll(0, myForm.scroll_top.value);
  }
});
</script>

複数のフォームに対応

以下は同じページに複数のフォームがある場合でも、それぞれのフォームを送信するとその位置に表示するようにした例です。

この場合、それぞれの form 要素の name 属性には依存しませんが、隠しフィールドには、同じ name 属性 scroll_top を指定して、value 属性に PHP の変数を記述する必要があります。

同じページの2つ目のフォーム
<form name="myForm2" method="post">
  <div>
    <label for="name2">名前(2) </label>
    <input name="name2" id="name2" value="" size="20">
  </div>
  <button>送信</button>
  <!-- name 属性が scroll_top の隠しフィールドを設定 -->
  <input type="hidden" name="scroll_top" value="<?php echo isset($_REQUEST['scroll_top']) ? $_REQUEST['scroll_top']: ''; ?>">
</form>
//load イベントにリスナーを登録
window.addEventListener('load', () => {
  //そのページの全ての form 要素を取得
  const forms = document.forms;
  //垂直方向スクロール量を入れる変数の初期化
  let scrollTopValue = '';
  //全ての form 要素を for 文で処理
  for(let i=0; i<forms.length; i++) {
    //name 属性が scroll_top の要素がそのフォームにあれば
    if(forms[i].scroll_top) {
      //フォームの submit イベントを設定
      forms[i].addEventListener('submit', ()=> {
        //送信時の垂直方向のスクロール量を取得
        const scrollTop = window.scrollY ;
        //隠しフィールドに現在の垂直方向のスクロール量を設定
        forms[i].scroll_top.value = scrollTop;
      });
      //隠しフィールドで送信された値(垂直方向スクロール量)を変数に代入
      scrollTopValue = forms[i].scroll_top.value ;
    }
  }
  //垂直方向スクロール量が空でなければページが読み込まれたらスクロール
  if(scrollTopValue) {
    window.scroll(0, scrollTopValue);
  }
});

フォームコントロール

input 要素や select 要素、textarea 要素、button 要素などのコントロールはフォーム要素内に配置するとフォームの部品として機能しますが、単独でも入力コントロールなどとして使用することができます。

フォーム要素内に配置されたコントロールは Form オブジェクトの elements プロパティを使ってアクセスできますが、単独で配置されたコントロールは getElementById などの DOM のメソッドを使ってアクセスできます。

フォームコントロールで共通して使用できるプロパティとメソッド

フォームコントロールには、それぞれ固有のプロパティ(要素の属性)とメソッドがありますが、以下のプロパティやメソッドは共通して使用することができます。

プロパティ(属性) 説明
dsabled 要素の入力や選択を無効にする属性
form その要素が属するフォーム要素(Form オブジェクト)
labels その要素に関連付けられた label 要素のリスト(NodeList)。
name 要素に設定された名前(name 属性の値)
type 要素の種類(type 属性の値)
value value 属性に設定されている値や入力された値
メソッド 説明
blur() 要素からキーボードフォーカスを取り除きます
focus() 要素にフォーカスを設定します
各要素を操作するためのプロパティやメソッドを定義しているインターフェース
要素 インターフェース(MDN リンク)
button HTMLButtonElement
input(text, radio, checkbox 等) HTMLInputElement
textarea HTMLTextAreaElement
select HTMLSelectElement
fieldset HTMLFieldsetElement
HTML 要素共通 HTMLElement

値の取得と設定

input 要素や textarea 要素の入力された値の取得や設定は value プロパティを使用します。

以下の場合、2つ目のコンソールへの出力は入力された値に関わらず常に初期値が出力されます。

<input type="text" id="my-input" value="My Input">

<script>
  const myTextInput= document.getElementById('my-input');
  myTextInput.addEventListener('change', ()=> {
    console.log(myTextInput.value); // 入力された値が出力される
    console.log(myTextInput.getAttribute('value')); //常に初期値(My Input)が出力される
  })
</script>

getAttribute('value') は HTML の value 属性に記述されている値や setAttribute('value') または defaultValue プロパティで設定された値を参照することができます。

value 属性の値と value プロパティは別物と考えるとわかりやすいかもしれません。

入力された値の取得や設定は value プロパティを使い、 HTML の value 属性に記述されている値は getAttribute('value') や setAttribute('value')、または defaultValue プロパティを使います。

テキストフィールド

input 要素の type 属性に text を指定するか type 属性を省略すると、単一行のテキスト入力欄(テキストフィールド)になります。

複数行の文章を入力させる場合は textarea 要素(テキストエリア)を使用します。

<input type="text" name="firstName" size="20" placeholder="First Name">

type 属性に password を指定した input 要素や HTML5 で新たに追加されたフォーム部品の type 属性(email, tel, url, range など)も1行入力欄のテキストフィールドです。

<input type="range" name="myRange" value="30" min="0" max="100" step="5">

必要に応じて value 属性に初期値を設定することができます。

<input name="country" size="20" value="日本"><!--この例では type 属性を省略 -->

テキストフィールドがフォーム内にある場合は、document.formselements を使って取得(アクセス)することができます。

以下は document.forms を使って name 属性が myForm の form 要素の name 属性が emailInput の elements プロパティ(input 要素)にアクセスしています。

<form name="myForm">
  <div>
    <label for="emailInput">E-mail: </label>
    <input type="email" name="emailInput" id="emailInput" value="" size="20">
  </div>
</form>

<script>
const emailElem = document.myForm.emailInput;
//以下でも同じこと ※ .forms は省略可能
//const emailElem = document.forms.myForm.emailInput;
//const emailElem = document.forms['myForm'].emailInput;
//const emailElem = document.forms.myForm['emailInput'];
//const emailElem = document.forms.myForm.elements['emailInput'];

//上記で取得した要素の type 属性をコンソールに出力
console.log(emailElem.type);  //email
</script>

フォーム内にない場合は(フォーム内にある場合でも)、 DOM のメソッドを使って取得(アクセス)することができます。

<label for="emailInput">E-mail: </label>
<input type="email" name="emailInput" id="emailInput" value="" size="20">

<script>
const emailElem = document.getElementById('emailInput');
//この例の場合、以下のいずれでも同じ
//const emailElem = document.querySelector('input[name="emailInput"]');
//const emailElem = document.getElementsByName('emailInput')[0];
//const emailElem = document.getElementsByTagName('input')[0];

console.log(emailElem.type);  //email
</script>

MDN HTMLInputElement

値の取得 value

テキストフィールドに入力されている値は value プロパティで取得できます。

HTML の value 属性に設定されている値は、defaultValue プロパティや getAttributes() で取得できます(初期状態では value プロパティと同じ)。

以下は Click と表示されたボタンをクリックするとテキストフィールドに入力された値とその文字数をアラート表示する例です。

文字列の長さ:length

文字列の長さを取得するには String オブジェクトのプロパティ length を使います。但し、空白文字も文字数としてカウントされます。必要に応じて String オブジェクトの trim() メソッドを使って前後の空白を削除します。

<input type="text" id="myText" size="20">
<button type="button" id="btn">Click</button>

<script>
  document.getElementById('btn').addEventListener('click', () => {
    //value プロパティで値を取得
    let myTextValue = document.getElementById('myText').value;
    //前後の空白を削除(間の空白は削除されない)
    myTextValue = myTextValue.trim();
    //前後の空白を覗いた文字数を length で取得
    const myTextLength = myTextValue.length;
    //値と文字数をアラート表示
    alert('入力値: ' + myTextValue + ' 文字数: ' + myTextLength);
  });
</script>

以下は name="check" のボタン(14行目)をクリックすると、テキストフィールドに入力されている値を取得してコンソールに出力する例です。

<form name="myForm" id="myForm">
  <div>
    <label for="name">Name: </label>
    <input type="text" name="name" id="name" size="30">
  </div>
  <div>
    <label for="email">E-mail: </label>
    <input type="text" name="email" id="email" size="30">
  </div>
  <div>
    <label for="tel">TEL: </label>
    <input type="text" name="tel" id="tel" size="30">
  </div>
  <input type="button" name="check" id="check" value="Check">
  <input type="reset" value="Reset">
</form>

ボタンの要素に addEventListener を使って click イベントを設定し、それぞれのテキストフィールドに入力されている値をコンソールに出力しています。

この例ではボタンは通常のボタン(type="button")なので、クリックしてもフォームのデータは送信されません。サーバーにデータを送信するには送信ボタン(type="submit")を使います。

フォーム内の要素には document.myForm(または document.forms.myForm)に続けてその要素の name 属性をプロパティとして指定してアクセスすることができ、その値は .value で取得できます。

//name 属性が check のボタン要素にクリックイベントを登録
document.myForm.check.addEventListener('click', ()=> {
  //name 属性が name のテキストフィールドの値
  const name = document.myForm.name.value;
  //name 属性が email のテキストフィールドの値
  const email = document.myForm.email.value;
  //name 属性が tel のテキストフィールドの値
  const tel = document.myForm.tel.value;
  console.log('名前: ' + name);
  console.log('メール: ' + email);
  console.log('電話: ' + tel);
});

//コンソールへの出力例
/*
名前: Foo
メール: foo@example.com
電話: 123-456-7890
*/ 

上記は以下のように 変数(myForm)に name 属性が myForm の form 要素を取得して、それを基点に書き換えることができます 。

//name 属性が myForm の form 要素
const myForm = document.myForm;
// または const myForm = document.forms.myForm; など

//name 属性が check のボタン要素にクリックイベントを登録
myForm.check.addEventListener('click', ()=> {
  //name 属性が name のテキストフィールドの値
  const name = myForm.name.value;
  //name 属性が email のテキストフィールドの値
  const email = myForm.email.value;
  //name 属性が tel のテキストフィールドの値
  const tel = myForm.tel.value;
  console.log('名前: ' + name);
  console.log('メール: ' + email);
  console.log('電話: ' + tel);
}); 

以下のように querySelector() を使ってそれぞれの要素にアクセスすることもできます。

//name 属性が myForm の form 要素
const myForm = document.querySelector('form[name="myForm"]');
//上記 form 要素 を基点に name 属性が check の要素(ボタン)を取得
const check_btn = myForm.querySelector('input[name="check"]');

check_btn.addEventListener('click', ()=> {
  //上記 form 要素 を基点に name name 属性が name の要素を取得
  const name = myForm.querySelector('input[name="name"]').value;
  const email = myForm.querySelector('input[name="email"]').value;
  const tel = myForm.querySelector('input[name="tel"]').value;
  console.log('名前: ' + name);
  console.log('メール: ' + email);
  console.log('電話: ' + tel);
});

また、この例の場合はそれぞれの要素に id 属性を付与してあるので getElementById() を使ってそれぞれの要素にアクセスすることもできます。要素へのアクセス方法は色々とあります(関連項目:要素の取得)。

//id 属性が myForm の要素
const myForm = document.getElementById('myForm');
//id 属性が check の要素
const check_btn = document.getElementById('check');

check_btn.addEventListener('click', ()=> {
  //getElementById() で要素にアクセスしてその値(.value)を取得
  const name = document.getElementById('name').value;
  const email = document.getElementById('email').value;
  const tel = document.getElementById('tel').value;
  console.log('名前: ' + name);
  console.log('メール: ' + email);
  console.log('電話: ' + tel);
});
エスケープ(サニタイジング)

ユーザなど外部から入力された値を innerHTML を使って挿入(出力)する場合などでは、不正なスクリプトが実行されないように出力する際に値をエスケープ(サニタイジング)するか検証する必要があります。

textContentinnerText を使って値を設定したり、insertAdjacentText() を使って挿入する場合は、値の特殊文字(& < >)はエスケープされるので、外部から入力された値を出力する場合は基本的に textContent や innerText を使うのが良いと思います。

textContent で値を挿入

以下は textContent を使って値を挿入する例です。

Check というボタンをクリックすると入力されている値を name="output" の textarea 要素の textContent に設定して出力します。リセットボタンをクリックするとデフォルトの動作の入力された値をリセットするのに加えて textarea 要素の textContent を空にして出力をクリアします。

<form name="myForm">
  <div>
    <label for="name">Name: </label>
    <input type="text" name="name" id="name" size="30">
  </div>
  <div>
    <label for="email">E-mail: </label>
    <input type="text" name="email" id="email" size="30">
  </div>
  <div>
    <label for="tel">TEL: </label>
    <input type="text" name="tel" id="tel" size="30">
  </div>
  <button type="button" name="check">Check</button>
  <button type="reset" name="clear">Reset</button>
  <div class="output_div">
    <textarea name="output" rows="3" cols="50" readonly></textarea>
  </div>
</form>

<script>
//name 属性が myForm の form 要素
const myForm = document.myForm;

//name="check" のボタンに click イベントのイベントリスナーを登録
myForm.check.addEventListener('click', () => {
  //name 属性が name のテキストフィールドの値
  const name = myForm.name.value;
  //name 属性が email のテキストフィールドの値
  const email = myForm.email.value;
  //name 属性が tel のテキストフィールドの値
  const tel = myForm.tel.value;
  //テキストエリアに textContent を使って値を挿入(値はエスケープされる)
   myForm.output.textContent =  '名前: ' + name + '\nメール: ' + email + '\n電話: ' + tel;
});

//name="clear" のボタン(リセットボタン)に click イベントのイベントリスナーを登録
myForm.clear.addEventListener('click', () => {
  //出力をクリア
  myForm.output.textContent = '';
});
</script>

サニタイジング用関数を作成

PHP には、エスケープ処理を行う htmlspecialchars() と言う関数が用意されていますが、JavaScript にはそれに該当する関数はありません。

以下は特殊文字をエスケープして無害化するサニタイジング用の関数 h() の例です。引数に与えられた文字列の中の特殊文字(& " ' < >)をエスケープして返します。サニタイジング(エスケープ処理)

サニタイジング用関数 h()
function h(str){
  return str.replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
} 

以下は、ボタンをクリックしたらテキストフィールドに入力された値をサニタイズしてテキストエリアに innerHTML を使って挿入して出力する例です。但し、この例の場合は前述の例のように innerHTML の代わりに textContent を使った方が簡単です。

<form name="myForm">
  <div>
    <label for="name">Name: </label>
    <input type="text" name="name" id="name" size="30">
  </div>
  <div>
    <label for="email">E-mail: </label>
    <input type="text" name="email" id="email" size="30">
  </div>
  <div>
    <label for="tel">TEL: </label>
    <input type="text" name="tel" id="tel" size="30">
  </div>
  <button type="button" name="check">Check</button>
  <button type="reset" name="clear">Reset</button>
  <div class="output_div">
    <textarea name="output" rows="3" cols="50" readonly></textarea>
  </div>
</form>
<script>
//サニタイジング用関数
function h(str){
  return str.replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
}

//name 属性が myForm の form 要素
const myForm = document.myForm;
//上記 form 要素(myForm)の name 属性が output の要素(テキストエリア)
const output = myForm.output;

myForm.check.addEventListener('click', ()=> {
  //name 属性が name のテキストフィールドの値
  const name = myForm.name.value;
  //name 属性が email のテキストフィールドの値
  const email = myForm.email.value;
  //name 属性が tel のテキストフィールドの値
  const tel = myForm.tel.value;
  //テキストエリアの値に h() でエスケープした値を出力
  output.innerHTML =  '名前: ' + h(name) + '\nメール: ' + h(email) + '\n電話: ' + h(tel);
});

myForm.clear.addEventListener('click', ()=> {
  //出力をクリア
  output.innerHTML = '';
});
</script> 
defaultValue(初期値)

必要に応じてテキストフィールドの value 属性に値を設定して初期値を設定して表示することができます。

value プロパティで取得する値はユーザの入力により変わりますが、value 属性に設定した初期値は defaultValue プロパティで参照することができます。

<form>
  <input type="text" name="city" value="初期値" size="30">
  <button type="reset">Reset</button>
</form>

type="reset" のリセットボタンをクリックすると、value 属性に設定した初期値が表示されます。value 属性を設定していない場合や、空の値を設定している場合はクリアされます。

必要であれば、JavaScript から defaultValue プロパティに値を設定して変更することもできます。

<form name="myForm">
  <div> City:
    <input type="text" name="inputCity" value="City Name" size="30">
  </div>
  <input type="button" name="check" value="Check">
  <input type="button" name="change" value="Change Default">
  <input type="reset" value="Reset">
  <input type="button" name="resetDefault" value="Reset Default">
  <div class="output_div">
    <label for="output">value(入力された値): </label>
    <textarea name="output" id="output" rows="1" cols="50" readonly></textarea>
    <label for="output-2">defaultValue(初期値): </label>
    <textarea name="output2" id="output-2"  rows="1" cols="50" readonly></textarea>
  </div>
</form>
<script>
//name 属性が myForm の form 要素
const myForm = document.myForm;
//myForm の name 属性が inputCity の要素(テキストフィールド)
const inputCity = myForm.inputCity;
//テキストフィールドの初期値(defaultValue プロパティ)を保存
const inputCityDefault = myForm.inputCity.defaultValue;

//「Check」ボタンにクリックイベントのイベントリスナーを登録
myForm.check.addEventListener('click', ()=> {
  //入力された値を出力
  myForm.output.textContent = inputCity.value;
  //初期値(defaultValue プロパティ)を出力
  myForm.output2.textContent = inputCity.defaultValue;
});

//「Change Default」ボタンにクリックイベントのイベントリスナーを登録
myForm.change.addEventListener('click', ()=> {
  //初期値(defaultValue プロパティ)を入力された値に変更
  inputCity.defaultValue = inputCity.value;
})

//「Reset Default」ボタンにクリックイベントのイベントリスナーを登録
myForm.resetDefault.addEventListener('click', ()=> {
  //初期値(defaultValue プロパティ)を保存した元の値にに戻す
  inputCity.defaultValue = inputCityDefault
})
</script>
City:

Check ボタンをクリックすると、現在入力されている値と初期値を表示します。

Change Default ボタンをクリックすると、defaultValue に現在入力されているを設定して変更ます。

Reset Default ボタンをクリックすると、defaultValue の値を元の値(保存した初期値)に戻します。

Reset ボタンをクリックすると、現在の defaultValue の値を表示します(デフォルトの動作)。

イベント

テキストフィールドがフォーム内に配置されている場合、フォームが送信される際の submiit イベントでその時点でテキストフィールドに入力されている値を確認するなどの処理ができます。

input 要素自体に発生するイベントについては イベントのタイミング を参照ください。

以下は送信ボタンをクリックするか、どちらかのテキストフィールドにカーソルを置いて return キーを押してフォームを送信する際に発生するフォームの submiit イベントで入力されている値を確認する例です。

input 要素には type="email" と required を指定して、入力した値がメールアドレスの形式でない場合や値が空の場合は HTML5 の検証を行うようにしています。

submiit イベントでは2つのメールアドレスが一致していない場合はメッセージを表示して、Event のメソッド preventDefault() でデフォルトの動作(この場合はフォームの送信)を中止しています。※ この記述をしないと、フォームは送信されてしまいます。

また、リセットボタンにはデフォルトの動作のコントロールのリセット以外に、表示されているエラーメッセージを非表示にするように click イベントを設定しています。

<form name="myForm" method="post">
  <div>
    <label for="email1">E-mail: </label><br>
    <input type="email" required name="email1" id="email1" size="20">
  </div>
  <div>
    <label for="email2">E-mail(確認):
      <span id="errorMsg" style="color: red;"></span> </label><br>
    <input type="email" required name="email2" id="email2" size="20">
  </div>
  <div>
    <input type="submit" name="send" value="送信">
    <input type="reset" name="reset" value="Reset">
  </div>
</form>
<script>
  //name 属性が myForm の form 要素
  const myForm = document.myForm;
  //メッセージを表示する id 属性が errorMsg の span 要素
  const errorMsg = document.getElementById('errorMsg');

  //フォームに submit イベントのイベントリスナーを登録
  myForm.addEventListener('submit', (e) => {
    //メッセージを表示する span 要素のテキストを空に
    errorMsg.textContent = '';
    //email1 と email2 の値が異なればメッセージを表示して送信を中止
    if(myForm.email1.value !== myForm.email2.value ) {
      errorMsg.textContent = "メールアドレスが一致しません。";
      //引数に渡されるイベント(e)のメソッドを使ってフォームの送信を中止
      e.preventDefault();
    }
  });

  //Reset ボタンをクリックしたらメッセージもクリア
  myForm.reset.addEventListener('click', () => {
    //メッセージを表示する span 要素のテキストを空に
    errorMsg.textContent = '';
  });
</script> 

コピペの禁止

以下は1つ目のメールアドレスを入力するテキストフィールドではコピーを禁止し、2つ目のメールアドレスを入力するテキストフィールドではペースト(貼り付け)を禁止する例です。但し、このようにすると使いづらいフォームになります。

前述の例に copypasteinput イベント(39行目〜70行目)を追加しています。HTML は同じです。

コピーの禁止では、copy イベントが発生したら、発生したイベント名を type プロパティで取得してメッセージに表示し、preventDefault() でデフォルトの動作(コピー)を中止しています(ペーストも同様)。

また、メッセージが表示されたままにならないように、入力操作が行われたら input イベントでメッセージをクリアしています。

<form name="myForm" method="post">
  <div>
    <label for="email1">E-mail: </label><br>
    <input type="email" name="email1" id="email1" size="20" required>
  </div>
  <div>
    <label for="email2">E-mail(確認):
      <span id="errorMsg" style="color: red;"></span> </label><br>
    <input type="email" name="email2" id="email2" size="20" required>
  </div>
  <div>
    <input type="submit" name="send" value="送信">
    <input type="reset" name="reset" value="リセット">
  </div>
</form>
  </div>
<script>
  //name 属性が myForm の form 要素
  const myForm = document.myForm;
  //メッセージを表示する id 属性が errorMsg の span 要素
  const errorMsg = document.getElementById('errorMsg');
  //name 属性が email1 の input 要素
  const inputEmail1 = myForm.email1;
  //name 属性が email2 の input 要素
  const inputEmail2 = myForm.email2;

  //フォームに submit イベントのイベントリスナーを登録
  myForm.addEventListener('submit', (e) => {
    //メッセージを表示する span 要素のテキストを空に
    errorMsg.textContent = '';
    //email1 と email2 の値が異なればメッセージを表示して送信を中止
    if(myForm.email1.value !== myForm.email2.value ) {
      errorMsg.textContent = "メールアドレスが一致しません。";
      //フォームの送信を中止
      e.preventDefault();
    }
  });

  //Reset ボタンをクリックしたらメッセージもクリア
  myForm.reset.addEventListener('click', () => {
    //メッセージを表示する span 要素のテキストを空に
    errorMsg.textContent = '';
  });

  //email1 のテキストフィールドに copy イベントのイベントリスナーを登録
  inputEmail1.addEventListener('copy', (e) => {
    // e.type で発生したイベント名を取得してメッセージを表示
    errorMsg.textContent = e.type + ' はできません。';
    //コピーを禁止(させない)
    e.preventDefault();
  });

  //email2 のテキストフィールドに paste イベントのイベントリスナーを登録
  inputEmail2.addEventListener('paste', (e) => {
    errorMsg.textContent = e.type + ' はできません。';
    //ペーストを禁止(させない)
    e.preventDefault();
  });

  //email1 のテキストフィールドに input イベントのイベントリスナーを登録
  inputEmail1.addEventListener('input', () => {
    //入力された内容が変わるとメッセージをクリア
    errorMsg.textContent = '';
  });

  //email2 のテキストフィールドに input イベントのイベントリスナーを登録
  inputEmail2.addEventListener('input', () => {
    //入力された内容が変わるとメッセージをクリア
    errorMsg.textContent = '';
  })

</script>

フォームを使わない例

フォームを使わず、ボタンをクリックしたら入力されている値を使って何からの処理をする場合は、ボタンの click イベントを使うことができます。その他にも input 要素自体のイベントを使うこともできます。

以下は Reverse というボタンをクリックすると入力された文字列を逆順に出力する例です。

この例ではそれぞれの要素に document.getElementById() でアクセスしています。

入力された文字列を逆順で出力するには、入力された値(.value)を String オブジェクトのメソッド split() で1文字ずつ分解し、それを配列のメソッド reverse() で逆順に並べ替え、配列のメソッド join() で連結しています。

<input type="text" id="textInput"  size="40">

<button type="button" id="reverse">Reverse</button>
<button type="button" id="clear" class="clear">Clear</button>

<div id="outputText" class="output"></div>

<script>
  const textInput = document.getElementById('textInput');
  const outputText = document.getElementById('outputText');

  //Reverse ボタンに click イベントのイベントリスナーを登録
  document.getElementById('reverse').addEventListener('click', () => {
    //入力された文字列を逆順にして出力
    outputText.textContent = textInput.value.split('').reverse().join('');
  });

  //Clear ボタンに click イベントのイベントリスナーを登録
  document.getElementById('clear').addEventListener('click', () => {
    //入力された値と出力をクリア
    outputText.textContent = '';
    textInput.value = '';
  });
</script> 
input イベント

input イベントは、input 要素、select 要素、 textarea 要素の value が変更されたときに発生します。

change イベントが要素の変更が終わったとき(ユーザーが確定したとき)に発生するのに対して、input イベントは 要素の value の値が変化するたびに発生します。

各イベントの発生するタイミングの違いについては次項の「イベントのタイミング」を参照ください。

また、type="checkbox" または type="radio" の input 要素(チェックボックスやラジオボタン)では、代わりに change イベントを使用したほうが互換性が高いようです。

テキストフィールドの input イベント

以下はテキストフィールドのイベントの1つ、input イベントを使ってテキストフィールドの値が変化するたびに値を出力する例です。

この例では name 属性が textInput のテキストフィールドを querySelector() を使って取得しています。

addEventListener ではアロー関数を使っているので、引数(e)として渡されるイベントの target (イベントを発生させたオブジェクト)でテキストフィールドを参照してその値(e.target.value)を出力先に設定しています(アロー関数の代わりに function() を使えば、this で参照できます)。

<input type="text" name="textInput" size="40" placeholder="テキストを入力">
<p id="outputText" class="output"></p>

<script>
//テキストフィールド(name 属性が textInput)の input 要素を取得
const textInput = document.querySelector('input[name="textInput"]');
//出力先の id 属性が output の p 要素を取得
const outputText = document.getElementById('outputText');

//テキストフィールドに input イベントを登録
textInput.addEventListener('input', (e) => {
  //出力先の p 要素の textContent にテキストフィールドに入力された値を設定
  outputText.textContent = e.target.value;
});
</script> 

input イベントの例

以下はテキストフィールドではなく、type="range" の input 要素(スライダー)に input イベントを設定して、スライダーの値を変更すると、リアルタイムで div 要素の大きさを変更する例です。

width: 50

height: 50

<p> width:
  <input type="range" name="width" min="5" max="300" value="50" step="1">
  <span id="boxWidth">50</span> </p>
<p> height:
  <input type="range" name="height" min="5" max="300" value="50" step="1">
  <span id="boxHeight">50</span> </p>
<div id="box"></div>

 <script>
//id="box" の div 要素
const sampleBox = document.getElementById('box');
//id="boxWidth" の span 要素
const boxWidth = document.getElementById('boxWidth');
//id="boxHeight" の span 要素
const boxHeight = document.getElementById('boxHeight');

//name='width' の input 要素(スライダー)に input イベントのイベントリスナーを登録
document.querySelector('input[name="width"]').addEventListener('input', (e) => {
  //width のスライダーの値
  const widthValue = e.currentTarget.value;
  //span 要素のテキストにスライダーの値を設定
  boxWidth.textContent = widthValue;
  //スライダーの値を div 要素の width に設定
  sampleBox.style.setProperty('width', widthValue + 'px');
});

//name='height' の input 要素(スライダー)に input イベントのイベントリスナーを登録
document.querySelector('input[name="height"]').addEventListener('input', (e) => {
  //height のスライダーの値
  const heighthValue = e.currentTarget.value;
  //span 要素のテキストにスライダーの値を設定
  boxHeight.textContent = heighthValue;
  //スライダーの値を div 要素の height に設定
  sampleBox.style.setProperty('height', heighthValue + 'px');
});
</script>

関連項目

イベントの一覧:MDN イベントリファレンス

イベントのタイミング

同じ要素に発生するイベントでもタイプによりそれらの発生するタイミングが異なります。

input 要素、textarea 要素、select 要素では以下の入力イベントが使用できます。

入力イベント
イベント 説明(発生するタイミング)
beforeinput 要素の値が変更されようとしているときに発生
input 要素の値が変更されるたびに発生
change 要素の変更が終わったとき(ユーザーが確定したとき)に発生。テキストフィールドやテキストエリアの場合はフォーカスを失った時にイベントが発生

また、テキストフィールドやテキストエリアでは上記以外にも keyup や focus、blur などのイベントを設定することができます。

その他のイベント(一部抜粋) MDN イベントリファレンス
イベント 説明(発生するタイミング)
blur 要素がフォーカスを失ったときに発生
focus 要素がフォーカスされたときに発生
keydown 任意のキーが押されたときに発生
keypress shift、fn、caps lock を除く任意のキーが押された状態にあるときに発生(非推奨→ keydown または beforeinput を使用)
keyup 任意のキーが (押された状態から) 解放されるときに発生

以下は異なるイベントを使ってテキストフィールドに入力された値を出力する例です。

テキストフィールドやテキストエリアの場合、change イベントは要素の変更が終わったとき(blur と同じタイミング)に発生しますが、input イベントや keyup イベントでは値が変更されるたびに発生します。

また、例えば beforeinput と keydown はほぼ同じタイミングで発生しますが、フォーカスが外れた際の挙動が異なっていたり、コピペでは発生しない等、イベントにより発生するタイミングが異なります。

そのため、処理する内容に応じて適切なイベントを選択します。

イベント 出力(イベント発生時に取得する値) 発生回数
input
beforeinput
change
keydown
keyup
focus
blur

上記はテキストフィールド(type="text" の input 要素)の例ですが、テキストエリア(textarea 要素)でも同じです。

以下は上記サンプルのコードです。

<input type="text" id="textInput" size="30" placeholder="テキストを入力">
<input type="button" id="clear" value="Reset">

<!-- 入力された値をそれぞれ発生したタイミングで出力欄(.output の td)に出力 -->
<table>
  <tr>
    <th >イベント</th>
    <th>出力</th>
    <th>発生回数</th>
  </tr>
  <tr>
    <td>input</td>
    <td class="output"></td>
    <td class="eventCount"></td>
  </tr>
  <tr>
    <td>beforeinput</td>
    <td class="output"></td>
    <td class="eventCount"></td>
  </tr>
  ・・・中略・・・
  <tr>
    <td>blur</td>
    <td class="output"></td>
    <td class="eventCount"></td>
  </tr>
</table>

<script>
//id 属性が textInput の要素(テキストフィールド)
const textInput = document.getElementById('textInput');
//クラスが output の td 要素の集まり(入力値の出力先)
const outputs = document.getElementsByClassName('output');
//クラスが eventCount の td 要素の集まり(カウントの出力先)
const eventCounts = document.getElementsByClassName('eventCount');
//イベントのリストの(配列)
const events = ['input','beforeinput','change','keydown','keyup','focus','blur'];
//それぞれのイベントの発生回数(0で初期化)
const counts = Array(outputs.length);
counts.fill(0);

//イベントリスナーオブジェクト(addEventListener の第2引数に指定)
const eventListeners = {};
//イベントごとにオブジェクトを作成
for(let i=0; i<events.length; i++) {
  eventListeners[events[i]] = {
    output : outputs[i],
    count : counts[i],
    countOut : eventCounts[i],
    handleEvent: function(e) {
      //output に指定された要素の textContent プロパティに入力された値を出力
      this.output.textContent = e.target.value;
      //発生回数を1増加
      this.count ++;
      //countOut に指定された要素の textContent プロパティに発生回数を出力
      this.countOut.textContent = this.count;
    }
  };
}

//addEventListener を使ってそれぞれのイベントを登録する関数の定義
function addMyEvents(eventTarget, event, output, count, countOut, eventListener) {
  //eventTarget に event で指定されたイベントを登録
  eventTarget.addEventListener(event, eventListener, false );
}

//上記関数を使って同じ要素に異なるイベントのイベントリスナーを登録
for(let i=0; i<events.length; i++) {
  addMyEvents(textInput, events[i], outputs[i], counts[i], eventCounts[i], eventListeners[events[i]]);
}

//id 属性が clear の要素に click イベントのイベントリスナーを登録
document.getElementById('clear').addEventListener('click', ()=> {
  //テキストフィールドの value プロパティに空文字を設定
  textInput.value = '';
  //td 要素の textContent プロパティに空文字を設定
  for(let i=0; i<events.length; i++) {
    outputs[i].textContent = '';
    eventCounts[i].textContent = '';
    //オブジェクトのカウントをリセット
    eventListeners[events[i]].count = 0;
  }
});
</script>

上記コードでは、addEventListener() の第2引数にリスナー関数の代わりにオブジェクトを指定して、handleEvent メソッドを実装し、プロパティで引数を渡しています。

以下のようにリスナー関数を使った場合、カウントのリセット(35行目)ができません(上記の方法以外に良い方法があるかもしれません)

カウントのリセットができない例
const textInput = document.getElementById('textInput');
const outputs = document.getElementsByClassName('output');
const eventCounts = document.getElementsByClassName('eventCount');
const events = ['input','beforeinput','change','keydown','keyup','focus','blur'];
let counts = Array(events.length);
counts.fill(0);

//addEventListener を使ってそれぞれのイベントを登録する関数の定義
function addMyEvents(eventTarget, event, output, count, countOut) {
  //eventTarget に event で指定されたイベントを登録
  eventTarget.addEventListener(event, (e) => {
    //output に指定された要素の textContent プロパティに入力された値を出力
    output.textContent = e.target.value;
    //発生回数を1増加
    count ++;
    //countOut に指定された要素の textContent プロパティに発生回数を出力
    countOut.textContent = count;
  });
}

//上記関数を使って同じ要素に異なるイベントのイベントリスナーを登録
for(let i=0; i<events.length; i++) {
  addMyEvents(textInput, events[i], outputs[i], counts[i], eventCounts[i]);
}

//id 属性が clear の要素に click イベントのイベントリスナーを登録
document.getElementById('clear').addEventListener('click', ()=> {
  //テキストフィールドの value プロパティに空文字を設定
  textInput.value = '';
  //td 要素の textContent プロパティに空文字を設定
  for(let i=0; i<events.length; i++) {
    outputs[i].textContent = '';
    eventCounts[i].textContent = '';
    //それぞれのカウントをクリアするつもり
    counts[i] = 0; //※ 実際にはクリアできない(それぞれの値は保持されたまま)
  }
}); 

テキストエリア

テキストエリアは複数行の文章を入力できるテキスト入力欄で textarea 要素を使います。

テキストフィールドとは異なり、改行することができます。

<textarea name="comment" rows="3" cols="50" placeholder="コメントを入力"></textarea>

また、input 要素とは異なり、開始タグと終了タグのペアで使い、タグの間(<textarea>〜</textarea>)に記述された内容が初期値として使われます。

<textarea name="comment" rows="3" cols="50">この文字列が初期値として表示されます</textarea>

テキストエリアがフォーム内にある場合は、document.formselements を使って取得(アクセス)することができます。

以下は document.forms を使って name 属性が myForm の form 要素の name 属性が comment の elements プロパティ(textarea 要素)にアクセスしています。

<form name="myForm">
  <div>
    <textarea name="comment" rows="3" cols="50"></textarea>
  </div>
</form>

<script>
const myTextarea = document.myForm.comment;

//以下でも同じこと ※ .forms は省略可能
//const myTextarea = document.forms.myForm.comment;
//const myTextarea = document.forms['myForm'].comment;
//const myTextarea = document.forms.myForm['comment'];
//const myTextarea = document.forms.myForm.elements['comment'];

console.log(myTextarea.cols);  //50
</script> 

フォーム内にない場合は(フォーム内にある場合でも)、 DOM のメソッドを使って取得(アクセス)することができます。

イベントはテキストフィールドとほぼ同じです。

MDN HTMLTextAreaElement

値の取得 value

textarea 要素には HTML の value 属性はありませんが、<textarea>〜</textarea> に入力された値や記述された初期値はテキストフィールド同様、value プロパティで取得できます。

以下はボタンがクリックされたらテキストエリアの値を取得し、値が空か空白のみの場合はアラートを表示し、そうでなければ取得した値を div 要素の innerText プロパティに設定して出力する例です。

innerText の代わりに textContent を使うとテキストエリアに入力された改行は反映されません。

<textarea name="textArea" id="textArea" cols="30" rows="5"></textarea>
<button type="button" id="btn">Click</button>
<div id="output"></div>

<script>
  document.getElementById('btn').addEventListener('click', () => {
    //テキストエリアに入力された値
    const textAreaValue = document.getElementById('textArea').value;
    if(textAreaValue.trim() ==='') {
      alert('値が入力されていないか空白文字です。')
    }else{
      document.getElementById('output').innerText = textAreaValue;
      //innerText の代わりに textContent を使うと改行は取り除かれます
    }
  }, false);
</script> 

textLength プロパティ

テキストエリアには、入力されている値の長さ(文字数)を表す読み取り専用のプロパティ textLength があります。textLength は value.length と同じです。

以下はテキストエリアに文字を入力すると、入力された文字数を表示し、100文字を超えると文字数を赤色で表示する例です。

0/100

以下の例では addEventListener のリスナー関数にアロー関数を使っているので、関数内でテキストエリアには e.currentTarget でアクセスしています。

テキストエリアの文字数は value.length または textLength で取得できます。空白文字や改行も文字数にカウントされます。

span 要素の文字色は setProperty() や style プロパティを使ってインラインスタイルで設定しています。

<textarea name="comment" rows="5" cols="50" placeholder="コメント"></textarea>
<p><span id="count">0</span>/100</p>

<script>
//テキストエリア要素(name="comment" のテキストエリアがページに1つだけある場合)
const textArea = document.querySelector('textarea[name="comment"]');
//文字数を出力する span 要素
const countOut = document.getElementById('count');
//上記 span 要素のスタイル
const countOutStyle = countOut.style;

//テキストエリアに input イベントを登録
textArea.addEventListener('input', (e) => {
  //テキストエリアに入力されている文字の長さ(文字数)
  const count = e.currentTarget.value.length; //または e.currentTarget.textLength;

  //span 要素に文字数を出力
  countOut.textContent = count;

  //文字数が100より大きい場合は文字を赤色に
  if(count > 100) {
    countOutStyle.setProperty('color', 'red');
    // または countOutStyle.color = 'red';
  }else{
    //100文字未満の場合は文字を元に戻す
    countOutStyle.removeProperty('color');
    // または countOutStyle.color = null;
  }
});
</script>

上記の例では、文字色の変更はインラインスタイルで設定していますが、別途クラスでスタイルを設定しておき、以下のようにクラスの操作で変更することもできます(HTML は同じなので省略)。

CSS
.warning {
   color: #fff;
   background-color: red;
   padding: 2px;
 }
JavaScript
const textArea = document.querySelector('textarea[name="comment"]');
const countOut = document.getElementById('count');

textArea.addEventListener('input', (e) => {

  const count = e.currentTarget.value.length;
  countOut.textContent = count;

  //文字数が100より大きい場合は文字のスタイルを変更
  if(count > 100) {
    // warning クラスを追加
    countOut.classList.add('warning');
  }else{
    // warning クラスを削除
    countOut.classList.remove('warning');
  }
});
改行 \n

テキストフィールド(type="text" の input 要素)は1行の入力フィールドなので改行することができませんが、テキストエリア(textarea 要素)では入力時や値の設定時に改行することができます。

テキストエリアに改行を入れるには改行コード(\n:バックスラッシュと小文字の n)を使います。

また、テキストエリアに値を設定するには値の取得同様 value 属性を使います。

<textarea id="myTextarea"></textarea>
<button type="button" id="setTextarea1">改行なし</button>
<button type="button" id="setTextarea2">改行あり</button>
<script>
//テキストエリア
const myTextareaElem = document.getElementById('myTextarea');

//改行なしの文字列
const noLineBreak = 'Hello World!'
//改行(\n)を含む文字列
const withLineBreak = 'Hello \nWorld!'

document.getElementById('setTextarea1').addEventListener('click', () => {
  //改行なしの文字列をテキストエリアに設定
  myTextareaElem.value = noLineBreak;
});

document.getElementById('setTextarea2').addEventListener('click', () => {
  //改行を含む文字列をテキストエリアに設定
  myTextareaElem.value = withLineBreak;
});
</script>

または、バッククォート(`)を使ったテンプレートリテラルで記述しても改行が反映されます。

//テンプレートリテラル
const withLineBreak = `Hello
World!`;

入力された値を出力

テキストエリアに入力された値を出力する際に、textContentinnerText プロパティでは改行の扱いが異なります。

textContent を使った出力ではテキストエリアの改行は反映されませんが、innerText を使った出力では改行が反映されます(<br> が挿入されます)。

<textarea id="myTextarea" cols="50" rows="5"></textarea>
<button type="button" id="textContentOut">textContent</button>
<button type="button" id="innerTextOut">innerText</button>
<button type="button" id="clear">Clear</button>
<div id="myOutput"></div>

<script>
//テキストエリア
const myTextareaElem = document.getElementById('myTextarea');
//出力先の div 要素
const myOutputElem =  document.getElementById('myOutput');

document.getElementById('innerTextOut').addEventListener('click', () => {
  //テキストエリアに入力された値を出力先に innerText を使って設定
  myOutputElem.innerText = myTextareaElem.value;
});

document.getElementById('textContentOut').addEventListener('click', () => {
  //テキストエリアに入力された値を出力先に textContent を使って設定
  myOutputElem.textContent = myTextareaElem.value;
});

document.getElementById('clear').addEventListener('click', () => {
  //テキストエリアの値をクリア
  myTextareaElem.value = '';
  //出力先 div 要素の値をクリア
  myOutputElem.innerText = '';
});
</script>

改行を <br> に変換

テキストエリアに入力された値を innerHTML プロパティに設定して出力する場合などでは、改行コードは <br> に変換されないので、正規表現(String オブジェクトのメソッド)の replace() などを使って変換する必要があります。

以下は replace() を使って、文字列 str に含まれる全ての改行コード(\n)を <br> に変換する例です。

replace() の最初の引数は検索する文字列の正規表現で、この場合の検索対象は改行コードの \n で、一致するもの全てを検索するように g フラグを指定します(正規表現では文字列を / で囲みます)。

2番目の引数は置き換える文字列、この場合は改行タグの <br> になります。

let value = str.replace(/\n/g, '<br>');

以下のように関数にしておくこともできます。PHP には改行コードを <br> に変換する nl2br() という組み込み関数が用意されています。

//改行コードを <br> に変換する関数を定義
const nl2br = (str) => {
  return str.replace(/\n/g, '<br>');
}

//改行コードを含む文字列
let taString = 'Hello \nWorld!';
//nl2br() で改行コードを <br> に変換してコンソールに出力
console.log(nl2br(taString)); //Hello <br>World!

以下はボタンをクリックすると、テキストエリアに入力された値の改行コードを <br> に変換して、div 要素の innerHTML プロパティに設定して出力する例です。

入力された値を innerHTML プロパティを使って出力する際はエスケープして出力する必要があるので、以下では h() という関数で入力された値をエスケープしています。

<textarea id="myTextarea" cols="50" rows="5"></textarea>
<button type="button" id="convert">出力</button>
<button type="button" id="clear">クリア</button>
<div id="myOutput"></div>

<script>
//特殊文字をエスケープして無害化する関数
function h(str){
  return str.replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
}

//テキストエリア
const myTextareaElem = document.getElementById('myTextarea');
//出力先の div 要素
const myOutputElem =  document.getElementById('myOutput');

document.getElementById('convert').addEventListener('click', () => {
  //テキストエリアの値をエスケープ処理
  const escapedValue = h(myTextareaElem.value);
  //改行コードを <br> タグに変換
  const convertedValue = escapedValue.replace(/\n/g, '<br>');
  //出力先 div 要素の innerHTML プロパティに変換した値を設定
  myOutputElem.innerHTML = convertedValue;
});

document.getElementById('clear').addEventListener('click', () => {
  //テキストエリアの値をクリア
  myTextareaElem.value = '';
  /出力先 div 要素の値をクリア
  myOutputElem.innerHTML = '';
});
</script>

チェックボックス

input 要素の type 属性に checkbox を指定するとチェックボックスを生成します。関連するチェックボックス項目をグループとしてまとめる(認識させる)には name 属性に同じ値を指定します。

チェックボックスは複数選択が可能です。また、checked 属性を指定するとその項目はあらかじめチェックの付いた状態になります。

<input type="checkbox" name="music" value="jazz" checked> Jazz
<input type="checkbox" name="music" value="hiphop"> Hip Hop
<input type="checkbox" name="music" value="classic"> Classic
Jazz Hip Hop Classic

:checked 擬似クラス

:checked はチェックボックスやラジオボタン、オプション項目 (option 要素) がチェックされた場合に適用される CSS の擬似クラスです。

以下は :checked 擬似クラスを使って選択されたチェックボックスに続く span 要素の文字色を変更する例です。また label 要素を使ってそれぞれのチェックボックスと関連付けしているので、ラベルの文字をクリックしてもチェックボックスが選択・解除されます。

<div class="checkbox_sample">
  <input type="checkbox" name="music" id="cboxJazz" value="jazz" checked>
  <label for="cboxJazz"> Jazz </label>
  <input type="checkbox" name="music" id="cboxHiphop" value="hiphop">
  <label for="cboxHiphop"> Hip Hop </label>
  <input type="checkbox" name="music" id="cboxClassic" value="classic">
  <label for="cboxClassic"> Classic </label>
</div>
CSS
.checkbox_sample input:checked + label {
  color: red;
}

チェックボックスの取得

チェックボックスがフォーム内にある場合は、document.formselements を使って取得(アクセス)することができます。

同じ名前(値)の name 属性が複数ある場合、それらは配列のようなオブジェクト(NodeList)で、各要素にはインデックス(添字)を使ってアクセスします。

<form name="myForm">
  <input type="checkbox" name="music" value="jazz" checked> Jazz
  <input type="checkbox" name="music" value="hiphop"> Hip Hop
  <input type="checkbox" name="music" value="classic"> Classic
</form>

<script>
//name 属性が myForm の form 要素内にある name 属性が music の全ての要素
const musicCheckboxes = document.myForm.music;

//以下でも同じこと ※ .forms は省略可能
//const musicCheckboxes = document.forms.myForm.music;
//const musicCheckboxes = document.forms['myForm'].music;
//const musicCheckboxes = document.forms.myForm['music'];
//const musicCheckboxes = document.forms.myForm.elements['music'];

//配列のようなオブジェクトなので length プロパティがある
console.log(musicCheckboxes.length);   //3

//2番目の要素の値(value プロパティ)をコンソールに出力(インデックスを使ってアクセス)
console.log(musicCheckboxes[1].value); //hiphop
</script>

項目が1つだけの場合

チェックボックスの項目が1つだけ(同じ名前の name 属性が1つだけ)の場合、以下の方法でアクセスすると、その要素1つが取得され配列(のようなオブジェクト)ではありません。

<form name="myForm">
  <input type="checkbox" name="agree" value="agreed"> 同意する
</form>

<script>
const agreeCheckbox = document.myForm.agree;
//取得した要素の値(value プロパティ)を出力
console.log(agreeCheckbox.value);   //agreed
console.log(agreeCheckbox[0].value);   // 配列ではないので以下のエラー
//Uncaught TypeError: Cannot read property 'value' of undefined
</script>

チェックボックスがフォーム内にない場合は(フォーム内にある場合でも)、querySelectorAll()getElementsByName() などの DOM のメソッドを使って取得することができます。

以下の例では document.querySelectorAll() の引数に 'input[name="music"]' を渡していますが、環境に応じてセレクタを指定します。

<input type="checkbox" name="music" value="jazz" checked> Jazz
<input type="checkbox" name="music" value="hiphop"> Hip Hop
<input type="checkbox" name="music" value="classic"> Classic

<script>
//全ての name="music" の input 要素(NodeList)
const musicCheckboxes = document.querySelectorAll('input[name="music"]');

//getElementsByName で取得する場合
//const musicCheckboxes = document.getElementsByName('music');

console.log(musicCheckboxes.length);   //3
console.log(musicCheckboxes[2].value);  //classic
</script>

name 属性の値に [] を付けて配列としてデータを送信する

PHP でチェックボックスの値を配列で受け取る場合、以下のように name 属性の値に [] を付けて、配列としてデータを送信します。

<form name="myForm">
  <input type="checkbox" name="music[]" value="jazz" checked> Jazz
  <input type="checkbox" name="music[]" value="hiphop"> Hip Hop
  <input type="checkbox" name="music[]" value="classic"> Classic
  <button name="send">送信</button>
</form>

上記の場合、以下のいずれかで name="music[]" の要素の集まり(NodeList)にアクセスすることができます。

const musicCheckboxes1 = document.myForm['music[]'];

const musicCheckboxes2 = document.forms.myForm.elements['music[]'];

const musicCheckboxes3 = document.querySelectorAll('[name="music[]"]');

//当然ですが、以下ではアクセスできません(NG)
const musicCheckboxes1 = document.myForm.music[]; //エラー
//Uncaught SyntaxError: Unexpected token ']'

または、class を設定して getElementsByClassName() でアクセスするなど他にも方法はあります。

関連ページ: PHP 複数のチェックボックス

値の取得 value

チェックボックスの各要素の value 属性に設定されている値は value プロパティで取得できます。

以下は for 文を使ってチェックボックスの各要素の value 属性に設定されている値をコンソールに出力する例です。

<input type="checkbox" name="music" value="jazz" checked> Jazz
<input type="checkbox" name="music" value="hiphop"> Hip Hop
<input type="checkbox" name="music" value="classic"> Classic

<script>
//querySelector() で name="music" の最初の要素を取得してその value プロパティを出力
console.log(document.querySelector('input[name="music"]').value); //jazz

// querySelectorAll() で name="music" の全ての要素を取得
const musicCheckboxes = document.querySelectorAll('input[name="music"]');

for(let i=0; i<musicCheckboxes.length; i++) {
  //各要素の値をコンソールに出力
  console.log( 'musicCheckboxes[' + i + '] : ' + musicCheckboxes[i].value);
}

//以下は出力結果
//musicCheckboxes[0] : jazz
//musicCheckboxes[1] : hiphop
//musicCheckboxes[2] : classic
</script> 

musicCheckboxes は配列のようなオブジェクト(NodeList)なので NodeList のメソッド forEach() や ES6 の for of 文が使えます(いずれも IE 未対応)。

const musicCheckboxes = document.querySelectorAll('input[name="music"]');

//NodeList のメソッド forEach()
musicCheckboxes.forEach((elem,index) => {
  console.log('musicCheckboxes[' + index + '] : ' + elem.value);
});

//以下は出力結果
//musicCheckboxes[0] : jazz
//musicCheckboxes[1] : hiphop
//musicCheckboxes[2] : classic

//ES6 の for of 文
for (let elem of musicCheckboxes) {
  console.log(elem.value);
}

//以下は出力結果
//jazz
//hiphop
//classic
プロパティ

チェックボックスまたはラジオボタン(type 属性が checkbox または radio)には以下のようなプロパティがあります。

チェックボックスまたはラジオボタンに適用できるプロパティ
プロパティ 説明
checked 要素の現在の選択状態を参照または設定(真偽値)。選択されている場合は true、選択されていない場合は false
defaultChecked HTML で指定されていた選択状態を参照または設定(真偽値)。HTML で checked 属性が指定されている場合は true、指定されていない場合は false
indeterminate チェックボックスやラジオボタンの選択状態が不確定であるかどうかを返します。チェックボックスをクリックするとその値は false になります。

以下はチェックボックスの各要素のプロパティを確認及び変更する例です。

初期状態では、最初のチェックボックスの項目は checked 属性が指定されているので、checked と defaultChecked の値が true になっています。

checked や defaultChecked の値は変更(設定)可能です。また、checked の値はユーザーの操作により変化します。

<input type="checkbox" name="music" value="jazz" checked> Jazz
<input type="checkbox" name="music" value="hiphop"> Hip Hop
<input type="checkbox" name="music" value="classic"> Classic

<script>
const musicCheckboxes = document.querySelectorAll('[name="music"]');

//初期状態の各要素のプロパティを確認
for(let i=0; i<musicCheckboxes.length; i++) {
  console.log( i + ' checked : ' + musicCheckboxes[i].checked
                 + ' /defaultChecked : '+ musicCheckboxes[i].defaultChecked );
}

//出力結果
/*
0 checked : true /defaultChecked : true
1 checked : false /defaultChecked : false
2 checked : false /defaultChecked : false
*/

musicCheckboxes[0].defaultChecked = false;
musicCheckboxes[0].checked = false;

musicCheckboxes[1].defaultChecked = true;
musicCheckboxes[1].checked =  true;

// 上記設定後のプロパティの確認
for(let i=0; i<musicCheckboxes.length; i++) {
  console.log( i + ' checked : ' + musicCheckboxes[i].checked
                 + ' /defaultChecked : '+ musicCheckboxes[i].defaultChecked );
}

//出力結果
/*
0 checked : false /defaultChecked : false
1 checked : true /defaultChecked : true
2 checked : false /defaultChecked : false
*/

</script>
選択状態を取得

チェックボックスの選択状態を取得及び変更するには checked プロパティを使います。選択されている要素を取得するだけなら次項の :checked 擬似クラスを利用する方が簡単です。

チェックボックスの各要素の checked プロパティには、その要素が選択されている場合は true、選択されていない場合は false が格納されています。

以下の例では querySelectorAll() で name 属性が check のチェックボックスを全て取得して変数 checkboxes に格納しています。変数に格納されているのは配列のようなオブジェクトです。

ボタンがクリックされたら for 文でチェックボックスの各要素の checked プロパティを調べ、値が true の場合(そのチェックボックスが選択されている場合)はそのチェックボックスの値(value)とインデックスをコンソールに出力します。

<div>
  <input type="checkbox" name="check" value="1"> value 1
  <input type="checkbox" name="check" value="2"> value 2
  <input type="checkbox" name="check" value="3"> value 3
</div>
<button type="button" name="checkButton">Check</button>

<script>
//name="check" の全てのチェックボックスの要素を取得(NodeList)
const checkboxes = document.querySelectorAll('[name="check"]');
//name="checkButton" のボタン要素を取得
const btn = document.querySelector('[name="checkButton"]');

//ボタンに click イベントのイベントリスナーを登録
btn.addEventListener('click', () => {
  //for 文で各要素の checked プロパティを調べる
  for(let i=0; i<checkboxes.length; i++) {
    //checked プロパティが true の場合
    if(checkboxes[i].checked === true)  { // if(checkboxes[i].checked) でも同じ
      //checkboxes[i] は選択されているチェックボックスなのでその値とインデックスを出力
      console.log('index: ' + i + ' value: ' + checkboxes[i].value);
    }
  }
});
</script>

querySelectorAll() で取得した checkboxes は配列のようなオブジェクト(NodeList)なので NodeList のメソッド forEach() や ES6 の for of 文が使えます(いずれも IE 未対応)。

以下は16〜22行目の for 文を NodeList のメソッド forEach() で書き換えた例です。

btn.addEventListener('click', () => {
  //NodeList のメソッド forEach()
  checkboxes.forEach((elem, index) => {
    //checked プロパティが true の場合
    if (elem.checked) {
      console.log('index: ' + index + ' value: ' + elem.value);
    }
  });
});

以下は前述の例とほぼ同じですが、name 属性が music のチェックボックスを全て取得しておき、ボタンがクリックされたら各要素の checked プロパティを調べ、値が true の場合はそのチェックボックスの値を取得して配列 checked_list に追加し、出力先の div 要素の textContent プロパティに配列 checked_list の各要素を半角スペースで繋げた値を設定して出力しています。

<div>
  <input type="checkbox" name="music" id="cboxJazz" value="jazz" checked>
  <label for="cboxJazz"> Jazz </label>
  <input type="checkbox" name="music" id="cboxHiphop" value="hiphop">
  <label for="cboxHiphop"> Hip Hop </label>
  <input type="checkbox" name="music" id="cboxClassic" value="classic">
  <label for="cboxClassic"> Classic </label>
</div>
<button type="button" name="checkButton">Check</button>
<div id="output"></div>

<script>
//name="music" の全てのチェックボックスの要素を取得(NodeList)
const musicCheckboxes = document.querySelectorAll('[name="music"]');
//出力先の div 要素
const output = document.getElementById('output');

//ボタンに click イベントのイベントリスナーを登録
document.querySelector('[name="checkButton"]').addEventListener('click', () => {
  //選択されたチェックボックスの値を格納する配列
  const checked_list = [];
  //for 文で各要素の checked プロパティを調べる
  for(let i=0; i<musicCheckboxes.length; i++) {
    //checked プロパティが true の場合
    if (musicCheckboxes[i].checked) {
      //配列 hecked_list に値を追加
      checked_list.push(musicCheckboxes[i].value);
    }
  }
  //選択されたチェックボックスの値をスペース区切りで繋げて出力
  output.textContent = checked_list.join(' ');
});
</script>

以下は前述の例に「Select All」及び「Clear All」というボタンを追加して、「Select All」をクリックすると全てのチェックボックスを選択された状態にし、「Clear All」をクリックすると全てのチェックボックスの選択を解除します。

<div>
  <input type="checkbox" name="music" id="cboxJazz" value="jazz" checked>
  <label for="cboxJazz"> Jazz </label>
  <input type="checkbox" name="music" id="cboxHiphop" value="hiphop">
  <label for="cboxHiphop"> Hip Hop </label>
  <input type="checkbox" name="music" id="cboxClassic" value="classic">
  <label for="cboxClassic"> Classic </label>
</div>
<button type="button" name="checkButton">Check</button>
<button type="button" name="selectAll">Select All</button>
<button type="button" name="clearAll">Clear All</button>
<div id="output"></div>
<script>
//name="music" の全てのチェックボックス要素を取得
const musicCheckboxes = document.querySelectorAll('[name="music"]');
const output = document.getElementById('output');

//Check ボタンに click イベントのイベントリスナーを登録(前述の例と同じ)
document.querySelector('[name="checkButton"]').addEventListener('click', () => {
  const checked_list = [];
  for(let i=0; i<musicCheckboxes.length; i++) {
    if (musicCheckboxes[i].checked) { //(musicCheckboxes[i].checked === true)
      checked_list.push(musicCheckboxes[i].value);
    }
  }
  output.textContent = checked_list.join(' ');
});

//Select All ボタンに click イベントのイベントリスナーを登録(全てを選択状態に)
document.querySelector('[name="selectAll"]').addEventListener('click', () => {
  //ループで各要素の checked プロパティに true を設定
  for(let i=0; i<musicCheckboxes.length; i++) {
      musicCheckboxes[i].checked = true;
  }
});

//Clear All ボタンに click イベントのイベントリスナーを登録(全ての選択を解除)
document.querySelector('[name="clearAll"]').addEventListener('click', () => {
  //ループで各要素の checked プロパティに false を設定
  for(let i=0; i<musicCheckboxes.length; i++) {
      musicCheckboxes[i].checked = false;
  }
});
</script> 
選択されたチェックボックスを取得

選択されたチェックボックスを取得するには、前述のように対象の全てのチェックボックスの checked プロパティを調べる方法の他に、:checked 擬似クラスを使ったセレクタを querySelectorAll() に指定する方法があります。

以下はボタンをクリックしたら、その時点で選択された状態にあるチェックボックスの要素を querySelectorAll() を使って取得する例です。

querySelectorAll() の引数には :checked 擬似クラスを使った CSS セレクターを指定します。name 属性の値が check で選択されている状態の要素のセレクタは '[name="check"]:checked' と記述できます。

<div>
  <input type="checkbox" name="check" value="1"> value 1
  <input type="checkbox" name="check" value="2"> value 2
  <input type="checkbox" name="check" value="3"> value 3
</div>
<button type="button" name="checkButton">Check</button>

<script>
//name="checkButton" のボタン要素を取得
const btn = document.querySelector('[name="checkButton"]');

//ボタンに click イベントのイベントリスナーを登録
btn.addEventListener('click', () => {
  //選択されている(:checked)状態の name="check" の要素全てを取得(NodeList)
  const checkedItems = document.querySelectorAll('[name="check"]:checked');
  //選択されている状態の要素全ての値(value)を出力(全ての要素の checked プロパティは true)
  for(let i=0; i<checkedItems.length; i++) {
    console.log('value: ' + checkedItems[i].value);
  }
});
</script> 

以下もボタンがクリックされたら、選択された状態のチェックボックスを取得する例です。

<div>
  <input type="checkbox" name="music" id="cboxJazz" value="jazz" checked>
  <label for="cboxJazz"> Jazz </label>
  <input type="checkbox" name="music" id="cboxHiphop" value="hiphop">
  <label for="cboxHiphop"> Hip Hop </label>
  <input type="checkbox" name="music" id="cboxClassic" value="classic">
  <label for="cboxClassic"> Classic </label>
</div>
<button type="button" name="checkButton">Check</button>
<div id="output"></div>
<script>

//出力先の div 要素
const output = document.getElementById('output');
//name="music" の全てのチェックボックス要素(NodeList)
const musicCheckboxes = document.querySelectorAll('[name="music"]');

//Check ボタンに click イベントのイベントリスナーを登録
document.querySelector('[name="checkButton"]').addEventListener('click', () => {
  //name="music" の選択された(:checked の)チェックボックス要素
  const checkedBoxes = document.querySelectorAll('[name="music"]:checked');
  //選択されたチェックボックスの値を格納する配列
  const checked_list = [];
  //ループで各要素の値(value)を配列に追加
  for(let i=0; i<checkedBoxes.length; i++) {
      checked_list.push(checkedBoxes[i].value);
  }
  //選択されたチェックボックスの値を出力
  output.textContent = checked_list.join(' ');
});
</script>

また、この例では以下の CSS を設定して、選択されたチェックボックスの項目の文字色を赤にしています。

input:checked + label {
  color: red;
}
イベント

チェックボックスでは項目が選択・解除される際に input 及び change イベントが発生します。

input イベントは要素の値が変更されるたびに発生し、change イベントは要素の変更が終わったときに発生しますが、チェックボックスの場合は項目が選択・解除される際にほぼ同時に発生します(input イベントの方が先に発生します)。

HTML5 仕様書では、input イベントはユーザーがコントロールの状態を変更するたびに発生することになっていますが、チェックボックスやラジオボタンでは change イベントを使用するようにしたほうが互換性が高いようです(HTMLElement: input イベント)。

以下は change イベントを使って、選択及び解除された際にチェックボックスの value の値を出力する例です。この例の場合、同じ値の name 属性が複数あるので、その全ての要素を querySelectorAll() で取得しています。

そして for 文でそれぞれの要素に addEventListener() を使って change イベントのイベントリスナーを登録しています。

addEventListener() ではアロー関数を使っているので、イベントを登録した要素は e.currentTarget、発生した要素は e.target で参照できます(function 文を使えば this で、イベントを登録した要素を参照できます)。

発生した要素の checked プロパティを調べて true であれば、その要素が選択されたことになります。

<input type="checkbox" name="check" value="1"> value 1
<input type="checkbox" name="check" value="2"> value 2
<input type="checkbox" name="check" value="3"> value 3

<script>
//name 属性が check の要素を querySelectorAll() で全て取得
const checkboxes = document.querySelectorAll('[name="check"]');

//for 文で各要素にイベント処理を設定
for(let i=0; i<checkboxes.length; i++) {
  // 各要素に change イベントのリスナーを登録
  checkboxes[i].addEventListener('change', (e) => {
    //その要素(e.currentTarget)の checked プロパティを調べる
    if( e.currentTarget.checked ) {
      //true であれば選択された
      console.log(e.currentTarget.value + 'が選択されました。');
    }else{
      //false であれば(true でなければ)選択されていない
      console.log(e.currentTarget.value + 'が解除されました。');
    }
  })
}
</script> 

IE をサポートする必要がなければ、上記の for 文の代わりに NodeList のメソッド forEach() や ES6 の for of 文が使えます。

//ES6 の for of 文を使う場合
for(elem of checkboxes) {
  elem.addEventListener('change', (e) => {
    if( e.currentTarget.checked ) {
      console.log(e.currentTarget.value + 'が選択されました。');
    }else{
      console.log(e.currentTarget.value + 'が解除されました。');
    }
  })
}

//NodeList の forEach() メソッドを使う場合
checkboxes.forEach((elem) => {
  elem.addEventListener('change', (e) => {
    if( e.currentTarget.checked ) {
      console.log(e.currentTarget.value + 'が選択されました。');
    }else{
      console.log(e.currentTarget.value + 'が解除されました。');
    }
  })
});

以下はチェックボックスの選択状態が変更された際に発生する change 及び input イベントのタイミングを確認する例です。

ほぼ同じタイミングで発生した要素の値がそれぞれの出力先(id が changeEvent と inputEvent の span 要素)に表示されます。コンソールへの出力を確認すると input イベントの方が先に出力されています。

また、change イベントではその時点で選択されているチェックボックスの値(value)を「Checked Items」に出力しています。

<div>
  <label><input type="checkbox" name="check" value="1"> value 1 </label>
  <label><input type="checkbox" name="check" value="2"> value 2 </label>
  <label><input type="checkbox" name="check" value="3"> value 3 </label>
</div>
<p>change event: <span id="changeEvent"></span></p>
<p>input event: <span id="inputEvent"></span></p>
<p>Checked Items: <span id="checkedItems"></span></p>

<script>
//name 属性が check の要素を querySelectorAll() で全て取得
const checkboxes = document.querySelectorAll('[name="check"]');
//change イベントが発生した際にメッセージを出力する span 要素
const changeEventOut = document.getElementById('changeEvent');
//input イベントが発生した際にメッセージを出力する span 要素
const inputEventOut = document.getElementById('inputEvent');
//change イベントが発生した際に選択されているチェックボックスの値を出力する span 要素
const checkedItems = document.getElementById('checkedItems');
//選択された全てのチェックボックスの値を格納する配列
let checked_list = [];


//for 文で各要素に change イベントのイベントリスナーを登録
for(let i=0; i<checkboxes.length; i++) {
  checkboxes[i].addEventListener('change', (e) => {
    //イベントが発生したらコンソールに「change event」と出力
    console.log('change event');
    //イベントの発生した要素(e.target)の checked プロパティを調べる
    if( e.target.checked ) {
      //その要素が選択された場合(checked が true の場合)
      changeEventOut.textContent = e.target.value + 'が選択されました。';
    }else{
      //その要素の選択が解除された場合(checked が false の場合)
      changeEventOut.textContent = e.target.value + 'が解除されました。';
    }
    //選択されたチェックボックスの値を格納する配列を初期化
    checked_list = [];
    //全てのチェックボックスの checked を調べて true であれば配列に追加
    for(let j=0; j<checkboxes.length; j++) {
      if (checkboxes[j].checked) {
        checked_list.push(checkboxes[j].value);
      }
    }
    //選択された全てのチェックボックスの値を出力
    checkedItems.textContent = checked_list.join(' ');
  });
}

 //for 文で各要素に input イベントのイベントリスナーを登録
for(let i=0; i<checkboxes.length; i++) {
  checkboxes[i].addEventListener('input', (e) => {
    //イベントが発生したらコンソールに「input event」と出力
    console.log('input event');
    //イベントの発生した要素(e.target)の checked プロパティを調べる
    if( e.target.checked ) {
      //その要素が選択された場合(checked が true の場合)
      inputEventOut.textContent = e.target.value + 'が選択されました。';
    }else{
      //その要素の選択が解除された場合(checked が false の場合)
      inputEventOut.textContent = e.target.value + 'が解除されました。';
    }
  });
}
</script>

以下はそれぞれが独立した(name 属性の値が異なる)チェックボックスにイベントを設定する例で、チェックボックスを選択・解除することでその内容に合わせてリアルタイムで表示を変更します。

それぞれのチェックボックスに関連性はないので、個別にイベントリスナーを登録します。

チェックボックスのイベントは change を使っていますが、input イベントでもほぼ同じです。但し、スライダー(type="range" の input 要素)の変更をリアルタイムで反映されるには、input イベントを設定します(イベントのタイミング)。

<p id="target">Lorem ipsum dolor sit amet, ... blanditiis.</p>
<input type="checkbox" id="border" value="3px solid #ccc"> Border
<input type="checkbox" id="bgColor" value="#CEDDF7"> Background Color
<input type="checkbox" id="fontWeight" value="700"> Bold
<p> Padding:
  <input type="range" id="padding" min="0" max="30" value="0" step="1">
  <span id="paddingVal">0</span> </p>

<script>
//操作対象の id が target の p 要素
const target = document.getElementById('target');
//スライダーの値を出力する id が paddingVal の span 要素
const paddingVal = document.getElementById('paddingVal');

//id が border のチェックボックスにイベントリスナーを登録
document.getElementById('border').addEventListener('change', (e) => {
  if( e.currentTarget.checked ) {
    //チェックボックスが選択された場合(対象要素のスタイルを設定)
    target.style.setProperty('border', e.currentTarget.value);
  }else{
    //チェックボックスが解除された場合(対象要素のスタイルを削除)
    target.style.removeProperty('border');
  }
});

//id が bgColor のチェックボックスにイベントリスナーを登録
document.getElementById('bgColor').addEventListener('change', (e) => {
  if( e.currentTarget.checked ) {
    target.style.setProperty('background-color', e.currentTarget.value);
  }else{
    target.style.removeProperty('background-color');
  }
});

//id が fontWeight のチェックボックスにイベントリスナーを登録
document.getElementById('fontWeight').addEventListener('change', (e) => {
  if( e.currentTarget.checked ) {
    target.style.setProperty('font-weight', e.currentTarget.value);
  }else{
    target.style.removeProperty('font-weight');
  }
});

//id が padding の input 要素(スライダー)にイベントリスナーを登録
document.getElementById('padding').addEventListener('input', (e) => {
  //スライダーの値
  const paddingValue = e.currentTarget.value;
  //span 要素のテキストにスライダーの値を設定
  paddingVal.textContent = paddingValue;
  //スライダーの値を対象要素の padding に設定
  target.style.setProperty('padding', paddingValue + 'px');
});

</script>

上記の場合、イベントリスナーをチェックボックスに登録する操作は同じなので、以下のように関数にした方が記述が短くなります。

//イベントリスナーを登録する関数
const addMyChangeListener = (id, prop )=> {
  document.getElementById(id).addEventListener('change', (e) => {
    if( e.currentTarget.checked ) {
      //チェックボックスが選択された場合(対象要素のスタイルを設定)
      target.style.setProperty(prop, e.currentTarget.value);
    }else{
      //チェックボックスが解除された場合(対象要素のスタイルを削除)
      target.style.removeProperty(prop);
    }
  });
}
//上記関数を使ってリスナーを登録
addMyChangeListener('border', 'border');
addMyChangeListener('bgColor', 'background-color');
addMyChangeListener('fontWeight', 'font-weight');
イベントの移譲

親要素で子要素のイベントを検知

change イベントは input、select、textarea 要素においてユーザーによる要素の値の変更が確定したときに発生するイベントで、div 要素では発生しません。

但し、例えば div 要素の子要素にチェックボックスの input 要素がある場合、チェックボックスで発生したイベントは上位要素に順番に伝播(バブリング)します。

これを利用すると、div 要素にイベントリスナーを登録しておいてその子要素のイベントを捉えることができます(イベントの移譲/Event delegation)。

以下はチェックボックスを囲む div 要素に chnge イベントのイベントリスナーを登録し、チェックボックスを変更した際に発生する change イベントを検知する例です。

リスナー関数内では e.target がイベントが発生した要素になるので、その type 属性が checkbox であればチェックボックスで発生したイベントと判定しています。

そしてイベントの発生した要素の checked プロパティの値が true であればチェックボックスが選択されたことになるので、その値(e.target.value)をアラート表示しています。

checked プロパティの値が true でない(false の)場合は、チェックボックスの選択が解除されたことになります。

<div id="checkboxWrapper">
  <input type="checkbox" name="check" value="1">value 1
  <input type="checkbox" name="check" value="2">value 2
  <input type="checkbox" name="check" value="3">value 3
</div>
<script>
// チェックボックスを囲む div 要素
const wrapperDiv = document.getElementById('checkboxWrapper');

// div 要素に change イベントのリスナーを登録
wrapperDiv.addEventListener('change', (e) => {
  //イベントが発生した要素(e.target)の type 属性が checkbox であれば
  if( e.target.type === 'checkbox' ) {
    //checked プロパティが true であればチェックボックスが選択された
    if(e.target.checked === true) {
      alert('value ' + e.target.value + 'が選択されました');
    }else{
      alert('value ' + e.target.value + 'が解除されました');
    }
  }
});
</script>

全てのチェックボックスにイベントリスナーを登録しなくて済むので記述が簡単になります。また、動的にチェックボックスを追加してもそれらに対してイベントは適用されます。

以下もチェックボックスの親要素の div 要素に chnge イベントのイベントリスナーを登録し、チェックボックスを変更した際に発生する change イベントを検知する例です。

リスナー関数内では e.target がイベントが発生した要素になりますが、e.currentTarget はイベントを登録している要素(div 要素)になります。以下では確認のためにe.target と e.currentTarget に該当する要素の id の値を出力しています(38〜40行目)。

また、イベントが発生した時点で選択されているチェックボックスの要素は querySelectorAll() の引数に :checked 擬似クラスを使ったセレクタを指定して取得しています(43行目)。

<div id="checkboxWrapper">
  <input type="checkbox" name="check" value="1" id="checkbox1">
  <label for="checkbox1">value 1 </label>
  <input type="checkbox" name="check" value="2" id="checkbox2">
  <label for="checkbox2">value 2 </label>
  <input type="checkbox" name="check" value="3" id="checkbox3">
  <label for="checkbox3">value 3 </label>
</div>
<p>change event: <span id="changeEvent"></span></p>
<p>e.target: <span id="eTarget"></span></p>
<p>e.currentTarget: <span id="eCurrentTarget"></span></p>
<p>Checked Items: <span id="checkedItemsOut"></span></p>

<script>
// チェックボックスを囲む div 要素
const wrapperDiv = document.getElementById('checkboxWrapper');
// メッセージを出力する span 要素
const changeEventOut = document.getElementById('changeEvent');
// e.target の値を出力する span 要素
const eTarget = document.getElementById('eTarget');
// e.currentTarget の値を出力する span 要素
const eCurrentTarget = document.getElementById('eCurrentTarget');
// 選択されている要素の値を出力する span 要素
const checkedItemsOut = document.getElementById('checkedItemsOut');

wrapperDiv.addEventListener('change', (e) => {
  //イベントが発生した要素の type 属性が checkbox であれば
  if( e.target.type === 'checkbox' ) {
    //要素の checked プロパティを調べる
    if( e.target.checked ) {
      //checked プロパティが true の場合
      changeEventOut.textContent = e.target.value + 'が選択されました。';
    }else{
      //checked プロパティが true でない場合
      changeEventOut.textContent = e.target.value + 'が解除されました。';
    }
    //イベントの target プロパティで取得する要素の id 属性の値を出力
    eTarget.textContent = e.target.id;
    //イベントの currentTarget プロパティで取得する要素の id 属性の値を出力
    eCurrentTarget.textContent = e.currentTarget.id;
  }
  //選択されている(:checked)状態の name="check" の要素全て(NodeList)を取得
  const checkedItems = document.querySelectorAll('[name="check"]:checked');
  //選択されている全てのチェックボックスの値を格納する配列
  const checked_list = [];
  //NodeList の forEach() メソッドを使ってチェックボックスの値を配列に追加
  checkedItems.forEach((elem) => {
    checked_list.push(elem.value);
  });
  //選択された全てのチェックボックスの値を出力
  checkedItemsOut.textContent = checked_list.join(' ');
});
</script>

イベントを親要素に設定すれば、動的に子要素を追加・削除しても問題ありません(動的に追加/削除

ラジオボタン

input 要素の type 属性に radio を指定するとラジオボタンを生成します。チェックボックス同様、グループとしてまとめる(認識させる)には name 属性に同じ値を指定します。

チェックボックスは複数の項目を選択できますが、ラジオボタンは項目を一つしか選択できません。また、checked 属性を指定するとその項目はあらかじめ選択された状態になります。

<input type="radio" name="color" value="blue" checked>Blue
<input type="radio" name="color" value="red">Red
<input type="radio" name="color" value="green">Green
Blue Red Green

:checked 擬似クラス

:checked はラジオボタンやチェックボックス、オプション項目 (option 要素) がチェックされた場合に適用される CSS の擬似クラスです。

以下は :checked 擬似クラスを使って、選択されたラジオボタンに続く span 要素の文字色を変更する例です。以下では label 要素を使ってラベルとラジオボタンを関連付けしているので、ラベルの文字をクリックしてもラジオボタンが選択されます。

<div class="radiobutton_sample">
  <input type="radio" name="color" value="blue" id="colorBlue">
  <label for="colorBlue"> Blue </label>
  <input type="radio" name="color" value="red" id="colorRed">
  <label for="colorRed"> Red </label>
  <input type="radio" name="color" value="green" id="colorGreen">
  <label for="colorGreen"> Green </label>
</div>
CSS
.radiobutton_sample input:checked + label {
  color: red;
}

ラジオボタンの取得

ラジオボタンがフォーム内にある場合は、ラジオボタンのグループ(要素の配列)は document.formselements を使って取得することができます。

同じ名前(値)の name 属性が複数ある場合、それらは配列のようなオブジェクト(NodeList この場合は RadioNodeList )で、各要素にはインデックス(添字)を使ってアクセスします。

<form name="myForm">
  <input type="radio" name="color" value="blue"> Blue
  <input type="radio" name="color" value="red"> Red
  <input type="radio" name="color" value="green"> Green
</form>

<script>
//name 属性が myForm の form 要素内にある name 属性が color の全ての要素
const colorRadios = document.myForm.color;

//以下でも同じこと ※ .forms は省略可能
//const colorRadios = document.forms.myForm.color;
//const colorRadios = document.forms['myForm'].color;
//const colorRadios = document.forms.myForm['color'];
//const colorRadios = document.forms.myForm.elements['color'];

//配列のようなオブジェクトなので length プロパティがある
alert(colorRadios.length);   //3

//1番目の要素の値(value プロパティ)を表示(インデックスを使ってアクセス)
alert(colorRadios[0].value);   //blue
</script> 

ラジオボタンがフォーム内にない場合は(フォーム内にある場合でも)、querySelectorAll()getElementsByName() などの DOM のメソッドなどを使って取得することができます。

以下の例では document.querySelectorAll() の引数に 'input[name="color"]' を渡していますが、環境に応じてセレクタを指定します。

<input type="radio" name="color" value="blue"> Blue
<input type="radio" name="color" value="red"> Red
<input type="radio" name="color" value="green"> Green

<script>
//全ての [name="color"] の input 要素を querySelectorAll で取得
const colorRadios = document.querySelectorAll('input[name="color"]');

//getElementsByName で取得する場合
//const colorRadios = document.getElementsByName('color');

alert(colorRadios.length); //3
alert(colorRadios[1].value); //red
</script> 
値の取得 value

ラジオボタンの各要素の value 属性に設定されている値は value プロパティで取得できます。

以下は for 文を使ってラジオボタンの各要素の value 属性に設定されている値をコンソールに出力する例です。

<input type="radio" name="color" value="blue"> Blue
<input type="radio" name="color" value="red"> Red
<input type="radio" name="color" value="green"> Green

<script>
//全ての [name="color"] の input 要素を querySelectorAll で取得
const colorRadios = document.querySelectorAll('input[name="color"]');

//for 文で各要素の value 属性の値を出力
for(let i=0; i<colorRadios.length; i++) {
  //各要素の値(value プロパティ)をコンソールに出力
  console.log( 'colorRadios[' + i + '] : ' + colorRadios[i].value);
}

//以下は出力結果
//colorRadios[0] : blue
//colorRadios[1] : red
//colorRadios[2] : green
</script>  

colorRadios は配列のようなオブジェクト(NodeList)なので NodeList のメソッド forEach() や ES6 の for of 文が使えます(いずれも IE 未対応)。

選択状態を取得

ラジオボタンの選択状態を取得及び変更するには checked プロパティを使います(ラジオボタンとチェックボックスのプロパティ)。選択されている要素を取得するだけなら次項の :checked 擬似クラスを利用する方が簡単です。

ラジオボタンの各要素の checked プロパティには、その要素が選択されている場合は true、選択されていない場合は false が格納されています。

チェックボックスの場合は、複数の要素の checked プロパティが true になっている可能性がありますが、ラジオボタンの場合は checked プロパティが true になっている要素は1つだけです。

以下の例では querySelectorAll() で name 属性が color のラジオボタンを全て取得して変数 radioButtons に格納しています。変数に格納されているのは配列のようなオブジェクトです。

ボタンがクリックされたら for 文でラジオボタンの各要素の checked プロパティを調べ、値が true の場合(そのラジオボタンが選択されている場合)はそのチェックボックスの値(value)とインデックスをアラート表示します。

ラジオボタンの場合、選択されている項目は1つだけなので、選択されている項目が見つかればそれ以上 for 文を続ける必要はないので、break で for 文を抜け出しています。

<div>
  <label><input type="radio" name="color" value="blue">Blue</label>
  <label><input type="radio" name="color" value="red">Red</label>
  <label><input type="radio" name="color" value="green">Green</label>
</div>
<button type="button" id="checkSelected">Check</button>

<script>
//name="color" のラジオボタンの全ての要素を取得(NodeList)
const radioButtons = document.querySelectorAll('input[name="color"]');
//id が checkSelected のボタン要素を取得
const btn = document.getElementById('checkSelected');

//ボタンに click イベントのイベントリスナーを登録
btn.addEventListener('click', () => {
  //for 文で各要素の checked プロパティを調べる
  for(let i=0; i<radioButtons.length; i++) {
    //checked プロパティが true の場合(その要素が選択されている場合)
    if(radioButtons[i].checked === true)  { // if(radioButtons[i].checked) でも同じ
      //radioButtons[i] は選択されているラジオボタンなのでその値とインデックスをアラート表示
      alert('index: ' + i + ' value: ' + radioButtons[i].value);
      //選択されたいるラジオボタンは見つかったので for 文から抜け出す
      break;
    }
  }
})
</script>

以下は、name="color" のラジオボタンの全ての要素を取得しておいて、Check ボタンがクリックされたらラジオボタンの各要素の checked プロパティを調べて、値が true の要素があったらその要素の値(value)を出力し、出力先の文字色を value の値に設定します。

Clear ボタンをクリックするとラジオボタンの選択を解除(checked プロパティの値を false に)して、出力先のテキストを空('')にします。

<div>
  <label><input type="radio" name="color" value="blue">Blue</label>
  <label><input type="radio" name="color" value="red">Red</label>
  <label><input type="radio" name="color" value="green">Green</label>
</div>
<button type="button" id="check">Check</button>
<button type="button" id="clear">Clear</button>
<div id="output"></div>

<script>
//name="color" のラジオボタンの全ての要素を取得(NodeList)
const radioButtons = document.querySelectorAll('input[name="color"]');
//id が check のボタン要素を取得
const check = document.getElementById('check');
//id が clear のボタン要素を取得
const clear = document.getElementById('clear');
//id が output の div 要素を取得
const output = document.getElementById('output');

//ボタンに click イベントのイベントリスナーを登録
check.addEventListener('click', () => {

  //for 文で各要素の checked プロパティを調べる
  for(let i=0; i<radioButtons.length; i++) {
    //各要素の親要素(label 要素)の文字色のインラインスタイルをリセット
    radioButtons[i].parentElement.style.color = null;
    //checked プロパティが true の場合
    if(radioButtons[i].checked === true)  { // if(radioButtons[i].checked) でも同じ
      //変数 selectedRadio に 選択されているラジオボタンを代入
      selectedRadio = radioButtons[i];
      //ラジオボタンの値を出力
      output.textContent = selectedRadio.value;
      //出力先の文字色をラジオボタンの値に設定
      output.style.color = selectedRadio.value;
      // for 文から抜け出す
      break;
    }
  }
});

//Clear ボタンに click イベントのリスナーを登録
clear.addEventListener('click', () => {
  for(let i=0; i<radioButtons.length; i++) {
    //各要素の checked プロパティに false を設定(選択を解除)
    radioButtons[i].checked = false;
  }
  //出力先のテキストを空に
  output.textContent = '';
});
</script>

上記の例では、ラジオボタンの value に CSS の color に指定できる色の値の文字列を指定しているので出力先の文字色を value の値で設定しています。

もし、value の値とは別に色を指定して出力先などの文字色を変更するには、data- 属性や class 属性などを使って色を指定することもできます。

以下はラジオボタンの input 要素に独自の data-color 属性を指定する例です。

<input type="radio" name="color" data-color="#555CC3" value="blue">Blue
<input type="radio" name="color" data-color="#DC5254" value="red">Red
<input type="radio" name="color" data-color="#17860F" value="green">Green

この場合、それぞれの要素の data-color 属性の値は getAttribute('data-color') で取得できるので、前のコードの34行目を以下のように変更すれば出力先の文字色を指定した色に変更することができます。

//出力先の文字色をラジオボタンの data-color 属性の値に設定
output.style.color = selectedRadio.getAttribute('data-color');
選択されたラジオボタンを取得

選択されたラジオボタンを取得するには、前述のように対象の全てのラジオボタンの checked プロパティを調べる方法の他に、:checked 擬似クラスを使ったセレクタを querySelector() に指定する方法があります。

チェックボックスの場合は、選択されている要素が複数ある可能性があるため querySelectorAll() を使いますが、ラジオボタンの場合は選択されている要素は1つなので querySelector() を使った方が簡単です。

以下はボタンをクリックしたら、その時点で選択された状態にあるラジオボタンの要素を querySelector() で取得してその要素の値(value)をアラート表示する例です。

querySelector() の引数には :checked 擬似クラスを使った CSS セレクターを指定します。name 属性の値が color で選択されている状態の要素のセレクタは '[name="color"]:checked' と記述できます。

また、 querySelectorAll() では一致する要素がなければ空の NodeList を返しますが、querySelector() では一致する要素がない場合は null を返します。そのため要素が取得できない場合 selectedRadio.value はエラーになるため、アラート表示する際は要素が取得できた場合とそうでない場合に分岐しています。

<div>
  <label><input type="radio" name="color" value="blue">Blue</label>
  <label><input type="radio" name="color" value="red">Red</label>
  <label><input type="radio" name="color" value="green">Green</label>
</div>
<button type="button" id="checkSelected">Check</button>

<script>
//id が checkSelected のボタン要素を取得
const btn = document.getElementById('checkSelected');

//ボタンに click イベントのリスナーを登録
btn.addEventListener('click', () => {
  //name="color" のラジオボタンで選択されている(:checked の)要素を取得
  const selectedRadio = document.querySelector('[name="color"]:checked');
  if(selectedRadio){
    alert('value: ' + selectedRadio.value);
  }else{
    alert('何も選択されていません');
  }
})
</script> 

以下は前述のラジオボタンの各要素の checked プロパティを調べる例を、:checked セレクタを使って書き換えたものです。

<div>
  <label><input type="radio" name="color" value="blue">Blue</label>
  <label><input type="radio" name="color" value="red">Red</label>
  <label><input type="radio" name="color" value="green">Green</label>
</div>
<div>
<button type="button" id="check">Check</button>
<button type="button" id="clear">Clear</button>
</div>
<div id="output"></div>

<script>
//id が check のボタン要素を取得
const check = document.getElementById('check');
//id が clear のボタン要素を取得
const clear = document.getElementById('clear');
//id が output の div 要素を取得
const output = document.getElementById('output');

//ボタンに click イベントのイベントリスナーを登録
check.addEventListener('click', () => {
  //name="color" のラジオボタンで選択されている(:checked の)要素を取得
  const selectedRadio = document.querySelector('[name="color"]:checked');
  //selectedRadio が null でなければ(選択されているラジオボタンがあれば)
  if(selectedRadio){
    //親要素(label 要素)の文字色のインラインスタイルをリセット
    selectedRadio.parentElement.style.color = null;
    //変数 buttonValue に 選択されているラジオボタンの値を代入
    const buttonValue = selectedRadio.value;
    //ラジオボタンの値を出力
    output.textContent = buttonValue
    //出力先の文字色をラジオボタンの値に設定
    output.style.color = buttonValue;
  }
});

clear.addEventListener('click', () => {
  //name="color" のラジオボタンで選択されている(:checked の)要素を取得
  const selectedRadio = document.querySelector('[name="color"]:checked');
  //selectedRadio が null でなければ(選択されているラジオボタンがあれば)
  if(selectedRadio){
    // checked プロパティに false を設定して選択を解除
    selectedRadio.checked = false;
  }
  //出力先のテキストを空に
  output.textContent = '';
});
</script> 
イベント

ラジオボタンでは項目が選択される際に input 及び change イベントが発生します。

input イベントは要素の値が変更されるたびに発生し、change イベントは要素の変更が終わったときに発生しますが、ラジオボタンの場合は項目が選択される際にほぼ同時に発生します(input イベントの方が先に発生します)。

HTML5 仕様書では、input イベントはユーザーがコントロールの状態を変更するたびに発生することになっていますが、チェックボックスやラジオボタンでは change イベントを使用するようにしたほうが互換性が高いようです(HTMLElement: input イベント)。

以下は change イベントを使って、選択されたラジオボタンの value の値をアラート表示する例です。

同じ値の name 属性が複数あるので、その全ての要素を querySelectorAll() で取得して for 文でそれぞれの要素に addEventListener() を使って change イベントのイベントリスナーを登録しています。

addEventListener() ではアロー関数を使っているので、イベントが登録した要素は e.currentTarget で、イベントが発生した要素は e.currentTarget で参照します(function 文を使えば this で、イベントを登録した要素を参照できます)。

発生した要素の checked プロパティ(e.currentTarget.checked)を調べて true であれば、その要素が選択されたことになります。

<div>
  <label><input type="radio" name="color" value="blue"> Blue</label>
  <label><input type="radio" name="color" value="red"> Red</label>
  <label><input type="radio" name="color" value="green"> Green</label>
</div>

<script>
//name 属性が color の要素を querySelectorAll() で全て取得
const radios = document.querySelectorAll('[name="color"]');

//for 文で各要素に addEventListener() を設定
for(let i=0; i<radios.length; i++) {
  // change イベントのリスナーを登録
  radios[i].addEventListener('change', (e) => {
    //その要素(e.currentTarget)の checked プロパティが true であれば値(value)を表示
    if( e.currentTarget.checked ) {
      alert('選択された値 : ' + e.currentTarget.value);
    }
  });
}
</script> 

IE をサポートする必要がなければ、for 文の代わりに NodeList のメソッド forEach() や ES6 の for of 文が使えます。

ラジオボタンの場合、現在選択されているラジオボタン以外のボタンを選択すると、現在選択されていたボタンの選択は解除され、新たに選択したボタンが選択された状態になります。

但し、選択されていたボタンが解除される際には change や input イベントは発生しないようです。

以下はラジオボタンの各要素に change と input イベントのリスナーを設定して、イベントのタイプとイベントが発生した要素の checked プロパティの値をコンソールに出力する例ですが、イベントが発生した要素の checked プロパティの値はいつも true になります。

//name 属性が color の要素を querySelectorAll() で全て取得
const radios = document.querySelectorAll('[name="color"]');

//for 文で各要素に addEventListener() を設定
for(let i=0; i<radios.length; i++) {

  // change イベントのリスナーを登録
  radios[i].addEventListener('change', (e) => {
    //イベントのタイプとイベントが発生した要素の checked プロパティの値を出力
    console.log(e.type + ':' +  e.currentTarget.checked);
  });

  // input イベントのリスナーを登録
  radios[i].addEventListener('input', (e) => {
    //イベントのタイプとイベントが発生した要素の checked プロパティの値を出力
    console.log( e.type + ':' +  e.currentTarget.checked);
  });
}

/*出力例( checked プロパティの値はいつも true )
input:true  //input イベントが先に表示される
change:true
*/

※ ラジオボタンで発生する change や input イベントはその要素が選択された際に発生するので、発生した要素の checked プロパティの値はいつも true になります。

以下はラジオボタンの全ての要素に change イベントのリスナーを登録して、ラジオボタンが選択されたらその要素の値(value)を出力し、出力先の文字色を value の値に設定します。

<div>
  <label><input type="radio" name="color" value="blue">Blue</label>
  <label><input type="radio" name="color" value="red">Red</label>
  <label><input type="radio" name="color" value="green">Green</label>
</div>
<div id="output"></div>

<script>
//name="color" のラジオボタンの全ての要素を取得(NodeList)
const radioButtons = document.querySelectorAll('input[name="color"]');
//id が output の div 要素を取得
const output = document.getElementById('output');

//for 文で各要素に addEventListener() を設定
for(let i=0; i<radioButtons.length; i++) {
  // change イベントのリスナーを登録
  radioButtons[i].addEventListener('change', (e) => {
    //ラジオボタンの値を出力
    output.textContent = e.currentTarget.value;
    //出力先の文字色をラジオボタンの値に設定
    output.style.color = e.currentTarget.value;
  });
}
</script> 

change イベントのリスナーを登録では、以下のようにイベントが発生した要素の checked プロパティを調べてその要素が選択された状態かを確認することもできますが、イベントが発生する要素は選択された要素なので(その checked プロパティは true なので)、以下の5行目の if での判定は不要です。

for(let i=0; i<radioButtons.length; i++) {
  // change イベントのリスナーを登録
  radioButtons[i].addEventListener('change', (e) => {
    //イベントが発生した要素の checked プロパティが true であれば(必ず true)
    if(e.currentTarget.checked){   //省略可能→不要
      output.textContent = e.currentTarget.value;
      output.style.color = e.currentTarget.value;
    }
  });
}
イベントの移譲

チェックボックス同様、ラジオボタンでもイベント移譲(Event delegation)を利用できます。

以下はラジオボタンの親要素の div 要素に change イベントのリスナーを登録して、子要素のラジオボタンで発生したイベントを処理する例です。

リスナー内では発生したイベントの要素には引数で渡されるイベントの target プロパティ(以下では e.target)でアクセスできます。※ currentTarget プロパティはイベントを登録した要素(div 要素)になります。

イベントリスナーでは、発生したイベントの要素(e.target)の type 属性が radio であれば、ラジオボタンで発生した change イベントなので、その要素の値(value)をアラート表示しています。

<div id="radioWrapper">
  <label><input type="radio" name="color" value="blue">Blue</label>
  <label><input type="radio" name="color" value="red">Red</label>
  <label><input type="radio" name="color" value="green">Green</label>
</div>

<script>
//ラジオボタンを囲む div 要素
const wrapperDiv = document.getElementById('radioWrapper');

//div 要素に change イベントのリスナーを登録
wrapperDiv.addEventListener('change', (e) => {
  //イベントが発生した要素の type 属性が radio であれば
  if( e.target.type === 'radio' ) {
    //イベントが発生した要素(ラジオボタン)
    const selected = e.target;
    alert('選択されたラジオボタンの値:' + selected.value);
  }
});
</script> 

以下はラジオボタンの親要素にイベントリスナーを登録して、ラジオボタンが選択されたらその要素の値を出力し、出力先の文字色を value の値に設定する例です。

前述のラジオボタンの全ての要素にイベントリスナーを登録するのと同じことを行っています。

<div id="radioWrapper">
  <label><input type="radio" name="color" value="blue">Blue</label>
  <label><input type="radio" name="color" value="red">Red</label>
  <label><input type="radio" name="color" value="green">Green</label>
</div>
<div id="output"></div>

<script>
// ラジオボタンを囲む div 要素
const wrapperDiv = document.getElementById('radioWrapper');
//id が output の div 要素を取得
const output = document.getElementById('output');

wrapperDiv.addEventListener('change', (e) => {
  //イベントが発生した要素の type 属性が radio であれば
  if( e.target.type === 'radio' ) {
    //ラジオボタンの値を出力
    output.textContent = e.target.value;
    //出力先の文字色をラジオボタンの値に設定
    output.style.color = e.target.value;
  }
});
</script> 

セレクトボックス

セレクトボックスはセレクトボックス全体を定義する select 要素とその子要素として各項目を定義する option 要素で構成され、必要に応じて optgroup 要素で option 要素をグループ化することができます。

select 要素はフォームコントロールとみなされるので elements プロパティに含まれますが、option 要素や optgroup 要素は elements プロパティには含まれません。

セレクトボックスには単一選択型のプルダウンリストと複数項目を表示するリストボックスがあります。

select 要素に multiple 属性や size 属性を指定しない場合は単一選択型のプルダウンリストになります。

以下は単一選択型のプルダウンリストのセレクトボックスの例です。size 属性は省略していますが、size 属性に1を指定しても単一選択型のプルダウンリストになります。

項目を初期状態で選択状態にする selected 属性を option 要素のいずれにも指定していない場合は、最初の option 要素が選択状態になります。

<select name="borough">
  <option value="manhattan">Manhattan</option>
  <option value="brooklyn">Brooklyn</option>
  <option value="queens">Queens</option>
  <option value="bronx">Bronx</option>
  <option value="staten">Staten Island</option>
</select>  

option 要素に selected 属性を指定すると、その項目を初期状態で選択状態にします。以下は2番目の option 要素に selected 属性を指定しているので、その項目が表示(選択)されています。

<select name="borough">
  <option value="manhattan">Manhattan</option>
  <option value="brooklyn" selected>Brooklyn</option>
  <option value="queens">Queens</option>
  <option value="bronx">Bronx</option>
  <option value="staten">Staten Island</option>
</select>  

size 属性

multiple 属性を指定していない select 要素の size 属性に1より大きな値を指定すると単一選択型のリストボックスになります。

プルダウンリストの場合、デフォルトでは最初の項目が選択状態になりますが、単一選択型のリストボックスの場合、デフォルトではどの項目も選択されていない状態になります。

<select name="borough" size="5">
  <option value="manhattan">Manhattan</option>
  <option value="brooklyn">Brooklyn</option>
  <option value="queens">Queens</option>
  <option value="bronx">Bronx</option>
  <option value="staten">Staten Island</option>
</select>  

必要に応じて option 要素に selected 属性を設定して選択状態にすることができます。単一選択型のリストボックスで複数の option 要素に selected 属性を設定すると後の方の option 要素のみが選択状態になります。

<select name="borough" size="5">
  <option value="manhattan" selected>Manhattan</option>
  <option value="brooklyn">Brooklyn</option>
  <option value="queens">Queens</option>
  <option value="bronx">Bronx</option>
  <option value="staten">Staten Island</option>
</select>  

multiple 属性

select 要素に multiple 属性を指定すると、メニューの中から複数の項目を選択できる複数選択型のリストボックスになり、表示する項目の数は size 属性で指定することができます。

複数の項目を選択するには shift または command(Ctrl)キーを押しながらクリックします。

複数選択型のリストボックスの場合も単一選択型のリストボックス同様、デフォルトではどの項目も選択されていない状態になります。

<select name="borough" size="5" multiple>
  <option value="manhattan">Manhattan</option>
  <option value="brooklyn">Brooklyn</option>
  <option value="queens">Queens</option>
  <option value="bronx">Bronx</option>
  <option value="staten">Staten Island</option>
</select>

必要に応じて option 要素に selected 属性を設定して選択状態にすることができます。複数選択型のリストボックスの場合、複数の option 要素に selected 属性を設定することができます。

<select name="borough" size="5" multiple>
  <option value="manhattan" selected>Manhattan</option>
  <option value="brooklyn">Brooklyn</option>
  <option value="queens" selected>Queens</option>
  <option value="bronx">Bronx</option>
  <option value="staten">Staten Island</option>
</select>

optgroup 要素

optgroup 要素を利用すると、セレクトメニューの項目(option 要素)をグループ化することができます。

<select name="area" size="1">
  <optgroup label="Manhattan">
    <option value="uws">Upper West Side</option>
    <option value="ev">East Village</option>
    <option value="gramercy">Gramercy Park</option>
    <option value="les">Lower East Side</option>
  </optgroup>
  <optgroup label="Brooklyn">
    <option value="williamsburg">Williamsburg</option>
    <option value="gp">Green Point</option>
    <option value="flatbush">Flatbush</option>
    <option value="Red Hook">Red Hook</option>
  </optgroup>
</select> 
プロパティ

select 要素はフォームコントロールなので、input 要素など他のフォームコントロールと共通のプロパティとメソッドを持っていますが、以下のような固有のプロパティやメソッドがあります。

select 要素(HTMLSelectElement)のプロパティ(一部抜粋)
プロパティ 説明
length select 要素に含まれる option 要素の数
options select 要素に含まれる全ての option 要素を格納した配列のようなオブジェクト
selectedIndex 現在選択されている option 要素を示すインデックス番号。複数選択型のリストボックスで複数の option 要素が選択されている場合は選択されている「最初」の option 要素のインデックスの値になります。-1 は要素が選択されていないことを示します。
selectedOptions 選択されているすべての option 要素の集まり(配列のようなオブジェクト:HTMLCollection)。それぞれの要素にはインデックス(添字)や item() や name 属性が設定されていれば namedItem() でアクセスできます。
size HTML の size 属性の値。セレクトボックスに表示される項目数。HTML で明示的に size 属性を指定していない場合は単一選択型でも複数選択型でも 0 が返ります。
value 選択されている option 要素があれば最初の option 要素の value プロパティの値を返し、選択されている option 要素がなければ、空文字列を返します。選択されている option 要素に value 属性がない場合は、<option>テキスト</option> の「テキスト」の部分(option 要素の text プロパティ)を返します。
select 要素(HTMLSelectElement)のメソッド(一部抜粋)
メソッド 説明
add() option 要素を追加します。項目の追加・削除
item() 引数で指定した位置(インデックス番号)の option 要素を取得します。
namedItem() id または name 属性が設定されていれば、引数で指定した名前(id または name 属性の値)の option 要素を取得します。
remove() 指定したインデックス番号の option 要素を削除します。

options

options プロパティではその select 要素に含まれる全ての option 要素を格納した配列のようなオブジェクト(HTMLOptionsCollection)を取得できます。

このオブジェクトは全ての option 要素の他に select 要素と同じようなプロパティやメソッド(length、electedIndex、add、remove、item、namedItem)を持っています。

それぞれの要素には添字 [n](n はインデックス番号)や item(n) や name 属性が設定されていれば namedItem(name) でアクセスできます。

以下は select 要素に含まれる全ての option 要素のインデックス番号、value 属性の値、テキストを出力する例です。

<select name="selectBox">
  <option value="1">Foo</option>
  <option value="2">Bar</option>
  <option value="3">Baz</option>
</select>

<script>
// options プロパティを取得
const opts = document.querySelector('[name="selectBox"]').options;

//select 要素に含まれる全ての option 要素を for 文でループ
for(let i=0; i<opts.length; i++) {
  console.log(`index: ${opts[i].index}  value: ${opts[i].value}  text: ${opts[i].text}`);
}

/*
//出力結果
index: 0  value: 1  text: Foo
index: 1  value: 2  text: Bar
index: 2  value: 3  text: Baz
*/
</script>

以下は Chrome で options のオブジェクトプロパティを出力する例です。いくつかの options のプロパティ(add、remove、selectedIndex)は IE ではサポートされていません。

// options プロパティを取得
const opts = document.querySelector('[name="selectBox"]').options;

//options プロパティ(HTMLOptionsCollection)のオブジェクトプロパティを for in ループで調査
for(let prop in opts){
  console.log("プロパティ: " + prop + "  値: " + opts[prop] + "\n")
}

/*
出力結果
プロパティ: 0 値: [object HTMLOptionElement]  //option 要素
プロパティ: 1 値: [object HTMLOptionElement]  //option 要素
プロパティ: 2 値: [object HTMLOptionElement]  //option 要素
プロパティ: length 値: 3  //length プロパティ
プロパティ: selectedIndex 値: 0  //selectedIndex プロパティ
プロパティ: add 値: function add() { [native code] }  //add メソッド
プロパティ: remove 値: function remove() { [native code] }  //remove メソッド
プロパティ: item 値: function item() { [native code] }  //item メソッド
プロパティ: namedItem 値: function namedItem() { [native code] } //namedItem メソッド
*/

参考:HTMLOptionsCollection インタフェース

option 要素のプロパティ

option 要素(HTMLOptionElement)のプロパティ(一部抜粋)
プロパティ 説明
defaultSelected 初期値として選択されていたかどうかを表す真偽値(HTML の selected 属性の値)
index select 要素の中で何番目の option 要素であるかのインデックス番号
label HTML で label 属性が設定されていればその値。設定されていない場合は、要素のテキストコンテンツ(textContent の値)。
selected この要素が現在選択されているかどうかを示す真偽値
text この要素のテキストコンテンツ(textContent の値)
value value 属性が存在する場合はその値。存在しない場合は textContent の値
要素の取得

select 要素の取得

select 要素がフォーム内にある場合は、 document.formselements を使って取得することができます。

<form name="myForm">
  <select name="mySelect">
    <option value="manhattan">Manhattan</option>
    <option value="brooklyn">Brooklyn</option>
    <option value="queens">Queens</option>
    <option value="bronx" selected>Bronx</option>
    <option value="staten">Staten Island</option>
  </select>
</form>

<script>
//name 属性が myForm の form 要素内にある name 属性が mySelect の select 要素
const selectElem = document.myForm.mySelect;

//以下でも同じこと ※ .forms は省略可能
//const selectElem = document.forms.myForm.mySelect;
//const selectElem = document.forms['myForm'].mySelect;
//const selectElem = document.forms.myForm['mySelect'];
//const selectElem = document.forms.myForm.elements['mySelect'];

//select 要素の value プロパティ(選択された項目の値)
alert(selectElem.value);   //bronx
</script> 

select 要素がフォーム内にない場合は(フォーム内にある場合でも)、querySelector()getElementsByName() などの DOM のメソッドなどを使って取得することができます。

以下の例では document.querySelector() の引数に 'select[name="mySelect"]' を渡していますが、環境に応じてセレクタを指定します。

<div class="sample">
  <select name="mySelect">
    <option value="manhattan">Manhattan</option>
    <option value="brooklyn">Brooklyn</option>
    <option value="queens">Queens</option>
    <option value="bronx" selected>Bronx</option>
    <option value="staten">Staten Island</option>
  </select>
</div>

<script>
//name 属性が myForm の select 要素
const selectElem = document.querySelector('select[name="mySelect"]');

//getElementsByName で取得する場合(インデックスを指定)
//const selectElem = document.getElementsByName('mySelect')[0];

//select 要素の value プロパティ(選択された項目の値)
alert(selectElem.value);   //bronx
</script> 

option 要素の取得

select 要素の options プロパティで select 要素に含まれる全ての option 要素を(要素の集まりから成る配列のようなオブジェクトとして)取得することができます。

<form name="myForm">
  <select name="mySelect">
    <option value="manhattan">Manhattan</option>
    <option value="brooklyn">Brooklyn</option>
    <option value="queens">Queens</option>
    <option value="bronx" selected>Bronx</option>
    <option value="staten">Staten Island</option>
  </select>
</form>

以下は select 要素にアクセスしてその全ての option 要素を options プロパティを使って取得する例です。

//select 要素を取得
const selectElem = document.myForm.mySelect;
//select 要素の options プロパティで option 要素を取得
let optionElems = selectElem.options;

// 以下でも同じ
optionElems = document.myForm.mySelect.options;

// または
optionElems = document.querySelector('select[name="mySelect"]').options;

alert(optionElems.length);  //5

以下は options プロパティを使わずに querySelectorAll で取得する例です。

const optionElems = document.querySelectorAll('select[name="mySelect"] option');

alert(optionElems.length);  //5

個々の option 要素にアクセスするには、インデックス番号や item() メソッドを使います。option 要素に name 属性が指定されていれば、namedItem() メソッドで取得することもできます。

<form name="myForm">
  <select name="mySelect">
    <option name="mh" value="manhattan">Manhattan</option>
    <option name="bk" value="brooklyn">Brooklyn</option>
    <option name="qs" value="queens">Queens</option>
    <option name="bx" value="bronx">Bronx</option>
    <option name="si" value="staten">Staten Island</option>
  </select>
</form>

<script>
//インデックスが 0 の option 要素(selsect 要素のメソッド)
let firstOption = document.myForm.mySelect.item(0);
//以下でも同じ
firstOption = document.myForm.mySelect[0];

//以下は上記と同じこと
//options プロパティのインデックスが 0 の要素(options のメソッド)
firstOption = document.myForm.mySelect.options.item(0);
firstOption = document.myForm.mySelect.options[0];

console.log(firstOption.value); //manhattan

//name 属性が bk の option 要素
let secondOption = document.myForm.mySelect.namedItem('bk');

console.log(secondOption.value); //brooklyn
</script>
選択状態にする

select 要素の値を設定する(特定の option 要素を選択状態にする)には以下のような方法があります。

  1. select 要素の selectedIndex プロパティに option 要素のインデックス番号を設定する
  2. select 要素の value プロパティに option 要素の値を設定する
  3. option 要素の selected プロパティを true に設定する

以下は単一選択型の select 要素の値を設定する(特定の option 要素を選択状態にする)例で、上記のいずれの方法でも設定可能です。

単一選択型のプルダウンリストの場合、初期状態でいずれの option 要素にも selected 属性が設定されていない場合、最初の option 要素が選択されています。

select 要素に含まれる全ての option 要素は options プロパティで取得できます(25行目)。

<select name="mySelect">
  <option value="foo">Foo</option>
  <option value="bar">Bar</option>
  <option value="baz">Baz</option>
</select>

<script>
//select 要素を取得
const selectElem = document.querySelector('[name="mySelect"]');
//初期状態で selected 属性が設定されていないので最初の option 要素が選択されている
console.log(selectElem.value);  //foo
console.log(selectElem.selectedIndex); //0

//selectedIndex を1に(インデックスが1の option 要素を選択状態に)
selectElem.selectedIndex = 1;
console.log(selectElem.value);  //bar
console.log(selectElem.selectedIndex); //1

//select 要素の value に値を設定(value が baz の option 要素を選択状態に)
selectElem.value = 'baz';
console.log(selectElem.value);  //baz
console.log(selectElem.selectedIndex); //2

//インデックスが0の options(最初の option 要素)の selected プロパティを true に
selectElem.options[0].selected = true;
console.log(selectElem.value);  //foo
console.log(selectElem.selectedIndex); //0
</script>

複数の項目を選択状態にする

select 要素の selectedIndex や value プロパティを設定する方法では1つの要素しか選択状態にすることができません。そのため複数の項目を選択状態にするには、「option 要素の selected プロパティを true に設定する」方法を使います。

select 要素に含まれる全ての option 要素は options プロパティで取得できます。

また、「選択されている」全ての option 要素(HTMLCollection:配列のようなオブジェクト)は、select 要素の selectedOptions で取得できます。

以下は複数選択型のセレクトボックスで複数の項目(1番目と3番目)を選択状態にする例です。

<select name="mySelect" size="3" multiple>
  <option value="foo">Foo</option>
  <option value="bar">Bar</option>
  <option value="baz">Baz</option>
</select>

<script>
//select 要素を取得
const selectElem = document.querySelector('[name="mySelect"]');
//初期状態では選択されている option 要素がないので、value プロパティは空文字列を返す
console.log(selectElem.value);  // 空
//選択されている option 要素がないので、selectedIndex プロパティは -1 を返す
console.log(selectElem.selectedIndex); // -1

//options のインデックスが0と2の selected プロパティを true に
selectElem.options[0].selected = true;
selectElem.options[2].selected = true;

//選択されているすべての option 要素の数
console.log(selectElem.selectedOptions.length); //2

//選択されているすべての option 要素の値を出力
for(let i=0; i<selectElem.selectedOptions.length; i++) {
  console.log(selectElem.selectedOptions[i].value);
  // foo baz
}

//select 要素の value プロパティは選択されている「最初」の option 要素の value の値
console.log(selectElem.value);  //foo

//selectedIndex プロパティは選択されている「最初」の option 要素のインデックスの値
console.log(selectElem.selectedIndex); //0
</script>
値の取得 value

単一選択型(プルダウンリスト)のセレクトボックスで選択されている項目(option 要素)の値を取得するには、select 要素の value プロパティを使うのが簡単です。

選択されている項目のテキストを取得するには selectedIndexselectedOptions プロパティを使います(これらのプロパティを使えば値も取得できます)。

単一選択型の場合

select 要素の value プロパティで取得

select 要素の value プロパティは、選択されている最初の option 要素の value(値)を返すので、単一選択型セレクトボックスの選択されている項目の値を簡単に取得できます。

以下は Check ボタンをクリックすると、その時点で選択されている項目を出力する例です。

初期状態では最初の項目が選択状態になっています。最初の項目(option 要素)の value 属性は空なので、取得した select 要素の value プロパティが空であれば「項目が選択されていません」と出力するようにしています。

value:

<select name="mySelect">
  <option value="">選択してください</option>
  <option value="manhattan">マンハッタン</option>
  <option value="brooklyn">ブルックリン</option>
  <option value="queens">クイーンズ</option>
  <option value="bronx">ブロンクス</option>
  <option value="staten">スタテンアイランド</option>
</select>
  <button type="button" id="btn">Check</button>
<p>value:<span id="output"></span></p>
<script>
//select 要素を取得
const selectElem = document.querySelector('select[name="mySelect"]');
//ボタンの要素
const btn = document.getElementById('btn');
//出力先の要素
const output = document.getElementById('output');

//ボタンにクリックイベントを設定
btn.addEventListener('click', ()=> {
  //select 要素の value プロパティを取得
  const val = selectElem.value;
  //value プロパティの値が空でなければ値を出力
  if(val !=="") {
    //出力先のテキストに select 要素の value プロパティを設定
    output.textContent = val;
  }else{
    //値が空の場合は以下を出力
    output.textContent = "項目が選択されていません";
  }
});
</script> 

selectedIndex プロパティ

select 要素の selectedIndex プロパティには現在選択されている option 要素を示すインデックス番号が入っています。

selectedIndex プロパティの値を使えば、選択されている <option>〜</option> の「〜」の部分を取得することができます。

select 要素に含まれる全ての option 要素は select 要素の options プロパティで取得でき、各 option 要素にはそのインデックス番号でアクセスできます。

また、option 要素のテキストは option 要素の text プロパティで取得できます。

text:

<select name="mySelect">
  <option value="">選択してください</option>
  <option value="manhattan">マンハッタン</option>
  <option value="brooklyn">ブルックリン</option>
  <option value="queens">クイーンズ</option>
  <option value="bronx">ブロンクス</option>
  <option value="staten">スタテンアイランド</option>
</select>
  <button type="button" id="btn">Check</button>
<p>text:<span id="output"></span></p>
<script>
//select 要素を取得
const selectElem = document.querySelector('select[name="mySelect"]');
//ボタンの要素
const btn = document.getElementById('btn');
//text の出力先の要素
const output = document.getElementById('output');

//ボタンにクリックイベントを設定
btn.addEventListener('click', ()=> {
  //select 要素の selectedIndex プロパティを取得
  const index = selectElem.selectedIndex;
  //選択されている option 要素の text プロパティを取得(値を取得するには value を指定)
  const text = selectElem.options[index].text;
  //出力先に取得したテキストを設定
  output.textContent = text;
  //上記は以下のように1行にまとめることができます
  //output.textContent = selectElem.options[selectElem.selectedIndex].text;
});
</script> 

上記の24行目では option 要素は select 要素の options プロパティを使ってアクセスしていますが、以下のようにインデックス番号や item() メソッドを使ってアクセスすることもできます。

上記の場合、以下はいずれも同じことです。

//select 要素の options プロパティにインデックス番号を指定
const text = selectElem.options[index].text;
//select 要素にインデックス番号を指定
const text = selectElem[index].text;
//select 要素の item() メソッドにインデックス番号を指定
const text = selectElem.item(index).text;

selectedOptions プロパティ

selectedOptions プロパティは「選択されている」全ての option 要素を含む配列のようなオブジェクトで、このプロパティを使って選択されている option 要素の value や text を取得することもできます。

selectedOptions は IE では未対応です。

単一選択型の場合、選択されている option 要素は1つですが、selectedOptions プロパティが返す値は配列(のようなオブジェクト)なので、先頭の要素 [0] を取得します。

以下は selectedOptions プロパティを使って選択されている項目のテキストを取得する例です。

<select name="mySelect">
  <option value="">選択してください</option>
  <option value="manhattan">マンハッタン</option>
  <option value="brooklyn">ブルックリン</option>
  <option value="queens">クイーンズ</option>
  <option value="bronx">ブロンクス</option>
  <option value="staten">スタテンアイランド</option>
</select>
<button type="button" id="btn">Check</button>
<p>text:<span id="output"></span></p>
<script>
//select 要素を取得
const selectElem = document.querySelector('select[name="mySelect"]');
//ボタンの要素
const btn = document.getElementById('btn');
//text の出力先の要素
const output = document.getElementById('output');

//ボタンにクリックイベントを設定
btn.addEventListener('click', ()=> {
  //selectedOptions プロパティの先頭の要素(インデックス番号が0の要素)が選択されている要素
  const selectedOption = selectElem.selectedOptions[0];
  //選択されている option 要素の text プロパティを取得(値を取得するには value を指定)
  const text = selectedOption.text;
  //出力先に取得したテキストを設定
  output.textContent = text;
  //上記は以下のように1行にまとめることができます
  //output.textContent = selectElem.selectedOptions[0].text;
});
</script> 
複数選択型の場合

select 要素の value や selectedIndex プロパティが返すのは、「最初の」 option 要素の値(1つだけ)なので、それらを使って選択されている「複数の値」を取得するができません。

複数選択型の場合、選択されている「複数の値」を取得するには以下のような方法があります。

  • select 要素の selectedOptions プロパティを使う(※ IE は未対応)
  • select 要素の options プロパティや全ての option 要素の選択状態を調べる
  • :checked 擬似クラスを使ったセレクタを querySelectorAll() に指定する

selectedOptions プロパティを使う

以下は複数選択型のセレクトボックスで、Check ボタンをクリックすると選択されている全ての項目の value の値と選択されている項目数を出力する例です。

選択されている全ての option 要素は select 要素の selectedOptions プロパティで取得して、for 文で全ての値を取得しています。

Clear ボタンをクリックすると、選択されている全ての option 要素の selected プロパティに false を設定して選択を解除しています。また、その際に現在選択されている項目を示す selectedIndex プロパティに -1 を設定して現在選択されている項目もクリアしています。

value:

length:

<select name="mySelect" size="5" multiple>
  <option value="manhattan">マンハッタン</option>
  <option value="brooklyn">ブルックリン</option>
  <option value="queens">クイーンズ</option>
  <option value="bronx">ブロンクス</option>
  <option value="staten">スタテンアイランド</option>
</select>
<button type="button" id="btn">Check</button>
<button type="button" id="clear">Clear</button>
<p>value:<span id="outputValue"></span></p>
<p>length:<span id="outputLength"></span></p>

<script>
//select 要素を取得
const selectElem = document.querySelector('select[name="mySelect"]');
//value の出力先の要素
const outputValue = document.getElementById('outputValue');
//length の出力先の要素
const outputLength = document.getElementById('outputLength');

//Check ボタンにクリックイベントを設定
document.getElementById('btn').addEventListener('click', ()=> {
  //select 要素の selectedOptions プロパティで、選択されている option 要素を全て取得
  const selected = selectElem.selectedOptions;
  //選択された option 要素の値を格納する配列
  const selectedValues = [];
  //for 文で各要素の value プロパティを配列に追加
  for(let i=0; i<selected.length; i++) {
    selectedValues.push(selected[i].value);
  }
  //選択された option 要素の値をスペース区切りで繋げて出力
  outputValue.textContent = selectedValues.join(' ');
  //選択された option 要素の数を出力
  outputLength.textContent = selected.length;
});

//Clear ボタンにクリックイベントを設定
document.getElementById('clear').addEventListener('click', ()=> {
  //select 要素の selectedOptions プロパティで選択されている option 要素を全て取得
  const selected = selectElem.selectedOptions;
  for(let i=0; i<selected.length; i++) {
    //選択されている option 要素の selected プロパティを false にして選択を解除
    selected[i].selected = false;
  }
  //上記の代わりに以下でも同じ結果が得られます(selectedOptions の要素を削除)
  //selectElem.selectedOptions.length = 0;

  //select 要素の selectedIndex プロパティに -1 を指定して何も選択されていない状態に
  selectElem.selectedIndex = -1;
  //出力をクリア
  outputValue.textContent = "";
  outputLength.textContent = "";
});
</script>

IE にも対応するには、options プロパティの各要素の selected プロパティを調べます。

以下は上記の Check ボタンのイベント登録の部分(10〜23行目)を selectedOptions を使わずに書き換えた例です。

document.getElementById('btn').addEventListener('click', ()=> {
  //select 要素の options プロパティで全ての option 要素を取得
  const opts = selectElem.options;
  //選択された option 要素の値を格納する配列
  const selectedValues = [];
  //for 文で各要素の selected プロパティを調べる
  for(let i=0; i<opts.length; i++) {
    if(opts[i].selected) {
      //selected プロパティが true であれば配列に追加
      selectedValues.push(opts[i].value);
    }
  }
  outputValue.textContent = selectedValues.join(' ');
  //要素の値を格納する配列の長さが選択された要素の数
  outputLength.textContent = selectedValues.length;
});

:checked 擬似クラス

:checked はラジオボタンやチェックボックス、オプション項目 (option 要素) がチェックされた場合に適用される CSS の擬似クラスです。

ラジオボタンやチェックボックス同様、:checked 擬似クラスを使ったセレクタを querySelectorAll() に指定して、選択された項目を取得することができます。

以下は セレクタ option:checked を querySelectorAll() に指定して選択された項目の全てを取得して、それらのテキストを出力する例です。

text:

<select name="mySelect" size="5" multiple>
  <option value="manhattan">マンハッタン</option>
  <option value="brooklyn">ブルックリン</option>
  <option value="queens">クイーンズ</option>
  <option value="bronx">ブロンクス</option>
  <option value="staten">スタテンアイランド</option>
</select>
<button type="button" id="btn">Check</button>
<button type="button" id="clear">Clear</button>
<p>text:<span id="outputText"></span></p>
<script>
//value の出力先の要素
const outputText = document.getElementById('outputText');

//Check ボタンにクリックイベントを設定
document.getElementById('btn').addEventListener('click', ()=> {
  //option:checked をセレクタに指定して選択されている option 要素を全て取得
  const selectedElems = document.querySelectorAll('[name="mySelect"] option:checked');
  //選択された option 要素のテキストを格納する配列
  const selectedText = [];
  //for 文で各要素の text プロパティ(テキスト)を配列に追加
  for(let i=0; i<selectedElems.length; i++) {
    selectedText.push(selectedElems[i].text);
  }
  outputText.textContent = selectedText.join(' ');
});

//select 要素を取得
const selectElem = document.querySelector('select[name="mySelect"]');

//Clear ボタンにクリックイベントを設定
document.getElementById('clear').addEventListener('click', ()=> {
  //選択されている option 要素の選択を解除
  selectElem.selectedOptions.length = 0;
  selectElem.selectedIndex = -1;
  outputText.textContent = "";
});
</script>

上記の例では :checked 擬似クラスを使って選択された項目の背景色をオレンジにしています。

CSS
select[name="mySelect"] option:checked {
  background-image: linear-gradient(0deg, orange 0%, orange 100%);
}
/* background-color では適用されないので background-image を使用 */

但し、option 要素は置換要素として扱われるため、:checked でスタイルが適用される部分はブラウザにより異なり、上記の背景色変更の設定(CSS スタイル)は Safari などでは機能しません。

項目の追加・削除

セレクトボックスの項目(option 要素)を追加するには select 要素の add() メソッドを使います。

add() メソッドは引数に追加する option 要素とその位置(オプション)を指定します。第2引数に指定したインデックス番号または要素の前に option 要素が追加されます。

第2引数を省略または null を指定した場合は最後の位置に追加されます。

以下は新たにセレクトボックスを作成して既存の div 要素に追加する例です。

createElement() で select 要素と option 要素を生成し、option 要素には value 属性とテキストを設定して add() メソッドで select 要素に追加しています。最後に作成した select 要素を既存の div 要素に追加しています。

add() メソッドの第2引数に null を指定しているので option 要素の最後に追加されます(この場合第2引数を省略しても同じ)。

<div id="foo"></div>

<script>
//select 要素を生成
const selectElem = document.createElement('select');
//2つの option 要素を生成
const opt1 = document.createElement('option');
const opt2 = document.createElement('option');

//option 要素の value 属性を設定
opt1.value = "1";
//option 要素の text(テキスト)を設定
opt1.text = "Option 1";

opt2.value = "2";
opt2.text = "Option 2";

//select 要素に option 要素を追加
selectElem.add(opt1, null);  //add(opt1) でも同じ
selectElem.add(opt2, null);  //add(opt2) でも同じ

//既存の id が foo の div 要素に生成した select 要素を追加
document.getElementById('foo').appendChild(selectElem);
</script>

<div id="foo">
  <select>
    <option value="1">Option 1</option>
    <option value="2">Option 2</option>
  </select>
</div>

option 要素を作成するコンストラクタ

option 要素を作成するためのコンストラクタ Option() が用意されています。

let option = new Option(text, value, defaultSelected, selected);
引数 意味
text 表示するテキスト。省略した場合は空文字列("")
value value 属性の値。省略した場合は text の値
defaultSelected selected 属性を指定するかどうかの真偽値。省略した場合は false
selected 選択状態を設定する真偽値。既定値は false (未選択)

以下は Option() を使って option 要素を生成する例です。

const opt1 = new Option('Option 1', '1', true, true);

//上記は以下と同じこと
const opt1 = document.createElement("option");
opt1.text = "Option 1";
opt1.value = "1";
opt1.defaultSelected = true;
opt1.selected = true;

//以下のような option 要素が生成される
<option value="1" selected="">Option 1</option>

以下は既存の select 要素に option 要素を追加する例です。

<select name="mySelect">
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
</select>

<script>
//select 要素を取得
const mySelect = document.querySelector('[name="mySelect"]');
//追加する option 要素を生成
const opt0 = new Option(' --- ', '', true, true);
const opt3 = new Option('Option 3', '3');

//生成した opt0 を option 要素の先頭に追加
mySelect.add(opt0, 0);
//または mySelect.add(opt0, mySelect.options[0]);

//生成した opt0 を option 要素の末尾に追加
mySelect.add(opt3);
</script>

<!-- 上記の結果 -->
<select name="mySelect">
  <option value="" selected=""> --- </option>
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
  <option value="3">Option 3</option>
</select>

項目の削除 remove()

項目(option 要素)を削除するには remove() メソッドの引数にインデックス番号を指定します。

<select name="mySelect">
  <option value="" selected=""> --- </option>
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
  <option value="3">Option 3</option>
</select>

<script>
//select 要素を取得
const mySelect = document.querySelector('[name="mySelect"]');
//最初の option 要素を削除
mySelect.remove(0);
//残りの option 要素の3番目を削除
mySelect.remove(2);
</script>

<!-- 上記の結果 -->
<select name="mySelect">
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
</select>
イベント

セレクトボックスでは項目を選択する際に input 及び change イベントが発生します。

input イベントは要素の値が変更されるたびに発生し、change イベントは要素の変更が終わったときに発生しますが、セレクトボックスの場合は項目が選択される際にほぼ同時に発生します(input イベントの方が先に発生します)。

以下は単一選択型のセレクトボックスで、項目を選択するとその値とテキストを出力する例です。

value:

text:

この例では change イベントを使っていますが、input イベントでもほぼ同じ結果になります。

addEventListener() でアロー関数を使う場合、リスナーを登録した要素はイベントの currentTarget プロパティで取得できます。

select 要素の value プロパティには、選択された option 要素の値(value)が入っています。

選択された要素のテキストを取得するには、選択された要素のインデックスを selectedIndex で取得して、options にインデックスを指定して選択された option 要素を取得し、text を取得します。

<select name="mySelect">
  <option value="">選択してください</option>
  <option value="manhattan">マンハッタン</option>
  <option value="brooklyn">ブルックリン</option>
  <option value="queens">クイーンズ</option>
  <option value="bronx">ブロンクス</option>
  <option value="staten">スタテンアイランド</option>
</select>
<p>value: <span id="valueOut"></span></p>
<p>text: <span id="textOut"></span></p>

<script>
//select 要素を取得
const selectElem = document.querySelector('select[name="mySelect"]');
//value の出力先の要素
const valueOut = document.getElementById('valueOut');
//text の出力先の要素
const textOut = document.getElementById('textOut');

selectElem.addEventListener('change', (e) => {
  //リスナーを登録した select 要素を取得
  const elem = e.currentTarget;
  //select 要素の value プロパティ(選択されている option 要素の value)
  valueOut.textContent = elem.value
  //selectedIndex を options のインデックスに指定して選択されている要素を取得
  textOut.textContent = elem.options[elem.selectedIndex].text;
  //この場合リスナーを登録した要素とイベントが発生する要素は同じ
  //console.log(e.currentTarget === e.target); //true
});
</script> 

addEventListener() で function 文を使う場合、リスナーを登録した要素は this で取得できるので、以下のように記述しても同じです。

selectElem.addEventListener('change', function() {
  valueOut.textContent = this.value
  textOut.textContent = this.options[this.selectedIndex].text;
});

以下は複数選択型のセレクトボックスで、項目を選択するとそれらの値とテキストを出力する例です。

value:

text:

以下の例では selectedOptions を使って選択されている要素を取得しています。

<select name="mySelect" size="5" multiple>
  <option value="manhattan">マンハッタン</option>
  <option value="brooklyn">ブルックリン</option>
  <option value="queens">クイーンズ</option>
  <option value="bronx">ブロンクス</option>
  <option value="staten">スタテンアイランド</option>
</select>
<p>value: <span id="valueOut"></span></p>
<p>text: <span id="textOut"></span></p>

<script>
//select 要素を取得
const selectElem = document.querySelector('select[name="mySelect"]');
//value の出力先の要素
const valueOut = document.getElementById('valueOut');
//text の出力先の要素
const textOut = document.getElementById('textOut');

selectElem.addEventListener('change', (e) => {
  //リスナーを登録した select 要素を取得
  const elem = e.currentTarget;
  //選択された option 要素の値を格納する配列
  const selectedValues = [];
  //選択された option 要素のテキストを格納する配列
  const selectedText = [];
  //selectedOptions で選択されている option 要素を全て取得
  const selected = elem.selectedOptions;
  //選択されている option 要素の値とテキストを取得して配列に追加
  for(let i=0; i<selected.length; i++){
    selectedValues.push(selected[i].value);
    selectedText.push(selected[i].text);
  }
  //選択されている option 要素の値をスペース区切りで出力
  valueOut.textContent = selectedText.join(' ');
  //選択されている option 要素のテキストをスペース区切りで出力
  textOut.textContent = selectedValues.join(' ');
});
</script> 

以下は上記と同じことを selectedOptions プロパティを使わず、options で全ての option 要素を取得して、その selected プロパティを調べる例です。

selectElem.addEventListener('change', (e) => {
  const elem = e.currentTarget;
  const selectedValues = [];
  const selectedText = [];
  //options で全ての option 要素を取得
  const opts = elem.options;
  //それぞれの option 要素を調べて選択状態であれば値とテキストを取得して配列に追加
  for(let i=0; i<opts.length; i++){
    //selected が true であれば選択されている
    if(opts[i].selected) {
      selectedValues.push(opts[i].value);
      selectedText.push(opts[i].text);
    }
  }
  valueOut.textContent = selectedText.join(' ');
  textOut.textContent = selectedValues.join(' ');
});

項目を動的に生成

以下は2つのセレクトボックスがあり、最初のセレクトボックスの選択された項目により、2つ目のセレクトボックスの項目を動的に生成する例です。

最初のプルダウンメニューの最初の項目(選択してください)は選択できないように disabled 属性を指定し、初期状態で表示されるように selected 属性を指定しています。

2つ目のプルダウンメニューは、最初のプルダウンメニューで項目が選択された際に項目を選択するように初期状態では select 要素自体に disabled 属性を指定しています。

2番目のプルダウンメニューに表示する項目のデータ(subCategoryList)はキーに1番目の select 要素の各 option 要素の value を、値にその option 要素が選択された場合に表示する項目の配列を設定したオブジェクト(連想配列)になっています。

それぞれの select 要素を取得して変数に代入し、最初の name="category" の select 要素に change イベントのリスナーを登録しています。

リスナー関数では、2番目のプルダウンメニューの disabled 属性を解除し、一度全ての項目を削除して空にしています。そして、1番目のプルダウンメニューで選択された値を使って表示する項目のデータを取得し、option 要素を生成し select 要素に追加しています。

1番目のプルダウンメニューで選択された値が、2番目のプルダウンメニューに表示する項目のデータ(オブジェクト)のキーになっているので、キーを指定することで表示する項目の配列を取得できます。

項目の配列を取得したら、forEach() で配列のそれぞれの要素をテキストとした option 要素を生成し、select 要素に追加することで表示しています。

<select name="category">
  <option disabled selected>選択してください</option>
  <option value="wine">ワイン</option>
  <option value="sake">日本酒</option>
  <option value="beer">ビール</option>
</select>
<select name="subCategory" disabled>
  <option disabled selected>種類</option>
</select>

<script>
//subCategory の select 要素に表示する項目のデータ
const subCategoryList =
      {
        "wine": ["スティル", "スパークリング", "フォーティファイド", "フレーヴァード"],
        "sake": ["純米酒", "本醸造酒", "吟醸酒"],
        "beer": ["ラガー", "エール"]
      };

//select 要素を取得
const category = document.querySelector('select[name="category"]');
const subCategory = document.querySelector('select[name="subCategory"]');

category.addEventListener('change', () => {
  //subCategory の disabled を解除
  subCategory.disabled = false;
  //subCategory の option を削除(options の length を0にして内容を削除)
  subCategory.options.length = 0;
  //subCategory の最初の option 要素を作成
  const firstOption = document.createElement('option');
  firstOption.text = '種類を選択してください';
  firstOption.defaultSelected = true;
  firstOption.disabled = true;
  //subCategory に上記で作成した option 要素を追加
  subCategory.add(firstOption);
  //category の項目(option 要素)で選択された値を取得
  const selected = category.value;
  //上記 selected をキーに指定して表示する項目のデータを取得して各値につき option 要素を生成
  subCategoryList[selected].forEach( (item) => {
    let option = document.createElement('option');
    //option 要素のテキストにデータの値を設定
    option.text = item;
    //subCategory に option 要素を追加
    subCategory.add(option);
  });
});
</script>