- はじめに
- <input> 要素の disabled 属性 と readonly 属性の違い
- readonly 属性が有効なのはテキストコントロールに限られる
- <select> 要素の readonly 属性
- readonly 属性が効かないコントロールで readonly を模倣する4つの方法
- まとめ
はじめに
HTML 要素の disabled
属性と readonly
属性は、うっかりと間違った使い方をしてしまいがちです。
この記事では属性の挙動の違いを説明し、編集不可コントロールの正しい扱い方について見ていきます。
なお、ここでは以下の HTML をひな形として利用することにします。
<!DOCTYPE html> <html> <meta charset="utf-8"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <body> <div class="container m-5"> <form action="/" method="post"> ... <input type="submit" class="btn btn-primary"/> </form> </div> </body> </html>
<input> 要素の disabled 属性 と readonly 属性の違い
HTML の <input>
要素には disabled
と readonly
属性が存在します。
disabled
: コントロールが無効化され、フォームを Submit しても値の送信が行われないreadonly
: 値の変更は行えないが、コントロールは有効なので フォームを Submit すれば値の送信が行われる
それぞれのコントロールは以下のような表示となります。
disabled
とするとコントロールの見た目がグレーアウトされます。
readonly
を指定した場合はコントロールの見た目に変化はなく、フォーカスも当たりますが、値の変更ができません(上記例は Readonly 要素にフォーカスを当てた状態です)。
Bootstrap の CSS を適用した場合は、見た目が少し変わります。
以下のように定義した場合、
<div class="form-group row"> <label for="input1" class="col-sm-2 col-form-label">Disabled</label> <div class="col-sm-10"> <input type="text" class="form-control" id="input1" value="Text1" disabled> </div> </div> <div class="form-group row"> <label for="input2" class="col-sm-2 col-form-label">Readonly</label> <div class="col-sm-10"> <input type="text" class="form-control" id="input2" value="Text2" readonly> </div> </div>
表示は以下のように双方グレーアウトされた見た目になります(こちらも Readonly 要素にフォーカスを当てた状態です)。
readonly 属性が有効なのはテキストコントロールに限られる
テキストコントロール以外の、チェックボックスやラジオボタンといったコントロールでは readonly 属性は機能しません。
MDN のドキュメントによると以下の記載となっています。
メモ: テキスト入力のコントロールのみが読み取り専用にすることができるのに対し、その他のコントロール (チェックボックスやボタンなど) は、読み取り専用と無効化の識別がしにくいので、 readonly 属性は適用されません。
つまりテキスト入力欄以外のコントロールについては以下のように readonly
を付けたとしても readonly 属性は適用されません。
<div class="form-group row"> <div class="col-sm-3">Checkbox</div> <div class="col-sm-9"> <div class="form-check"> <input class="form-check-input" type="checkbox" id="check1" name="check1" value="1" readonly> <label class="form-check-label" for="check1">checkbox</label> </div> </div> </div> <fieldset class="form-group"> <div class="row"> <legend class="col-form-label col-sm-3 pt-0">Radios</legend> <div class="col-sm-9"> <div class="form-check"> <input class="form-check-input" type="radio" name="radios" id="radios1" value="option1" readonly> <label class="form-check-label" for="radios1">First radio</label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="radios" id="radios2" value="option2" readonly> <label class="form-check-label" for="radios2">Second radio</label> </div> </div> </div> </fieldset>
この場合は以下のような表示となり、
チェックの変更もできてしまいます。もちろんフォームを Submit すれば変更した値が送信されてしまいます。
そもそも readonly
属性は無効なので当然ですね。
<select> 要素の readonly 属性
先ほどの checkbox
や radio
と同じように、select
要素にも readonly
属性はありません。
最初に disabled
について見てみましょう。
<select name="select" class="custom-select" disabled> <option value="1">One</option> <option value="2">Two</option> <option value="3">Three</option> </select>
念の為ですが、<select name="select" class="custom-select" disabled="disabled">
でも同じ意味です。
以下のようになり、disabled とした場合は、変更もできなければフォームの Submit で値の送信も行われません。
readonly
属性を付けた場合は以下のようになります。
<select name="select" class="custom-select" readonly> <option value="1">One</option> <option value="2">Two</option> <option value="3">Three</option> </select>
select
要素には readonly
属性は無いので、指定したとしても普通の select
要素として機能します。つまりreadonly は機能せず、変更もSubmit で値の送信も行われます。
readonly 属性が効かないコントロールで readonly を模倣する4つの方法
select
要素を例に、readonly を模倣する方法を4つ紹介します。
(1) option 要素を disabled 指定する
option
要素に disabled
属性を付けることで readonly を模倣することができます。
<select name="select" class="custom-select"> <option value="1" disabled>One</option> <option value="2" selected>Two</option> <option value="3" disabled>Three</option> </select>
コントロールを選択しようとしても、初期値以外の option
を disabled
指定することで変更できなくなります。
もちろんフォームの Submit で値の送信が行われます。
(2) select コントロールの操作を無効化する
CSS pointer-events: none;
を指定することで、マウスクリック操作を無効化できます。
ただしこの場合でも、キーボード操作が可能となるため tabindex="-1"
を指定してフォーカスが当たらないようにします。
<select name="select" class="custom-select" style="pointer-events: none;" tabindex="-1"> <option value="1">One</option> <option value="2">Two</option> <option value="3">Three</option> </select>
コントロールの操作ができないので、値の変更が禁止され、readonly のように振る舞うことになります。
(3) disable 指定して hidden で値を送信する
コントロールを disabled
指定し、値の送信は hidden
で行うことができます。
<select name="select" class="custom-select" disabled> <option value="1">One</option> <option value="2" selected>Two</option> <option value="3">Three</option> </select> <input type="hidden" name="select" value="2">
この場合、以下のような表示になります。
コントロールは無効化されますが、フォームの Submit で hidden
値として送信されます。
(4) disable 指定して Submit 時に有効化する
コントロールを disabled
指定し、Submit 時にコントロールを有効化することができます。
<form id="form" action="/" method="post"> <div class="form-group"> <select name="select" class="custom-select" disabled> <option value="1">One</option> <option value="2">Two</option> <option value="3">Three</option> </select> </div> <input type="submit" class="btn btn-primary"/> </form>
フォームの Submit イベントでコントロールの disabled
を変更します。
const form = document.getElementById('form'); form.addEventListener('submit', event => event.target.querySelectorAll("input:disabled, select:disabled") .forEach(e => e.disabled = false) );
フォームの Submit でコントロールが有効化され、値が送信されます。
まとめ
HTML コントロールの disabled
属性 と readonly
属性の違いについて見てきました。
readonly
属性はテキスト項目の input
要素についてのみ有効で、それ以外のコントロールでは、指定したとしても意味を成しません。
readonly として機能させたい場合には特別な対応が必要になり、4種類の対応方法を紹介しました。
readonly
指定されたコントロールをグレーアウトするような CSS 定義がされていた場合、値が変更できてしまうことに気付かなかったり、disable
指定と区別がつかずサーバ側に値が渡ってこなくなったりと、間違いやすいところなので、しっかりと憶えておきたいところです。