HTML
It’s an attribute that completely removes a form control from user interaction and form submission, effectively disabling it.
disabled 属性
概要:disabled は何をする属性か
- 機能
- フォーム“コントロール”をユーザー操作から 完全に 無効化し、フォーム送信時にも値を送らせない。
- 無効化されたコントロールは、事実上 DOM 上の “装飾” に変わる。
- 仕様位置
-
-
- 典型例
- 送信ボタンを条件達成まで押させない、購読プランに応じて入力欄を非活性化。
<button type="submit" disabled>送信</button>
基本構文と適用可能要素
- 入力系
<input>
, <textarea>
, <select>
- type 不問。テキスト・チェックボックス等すべて
- 選択系
<option>
, <optgroup>
- 子要素にも波及
- ボタン系
<button>
- フォーム部品以外
- 直接は不可。代替は
aria-disabled
を使用
静的指定(HTML側)
<input type="number" name="age" disabled>
動的指定(JS側)
document.querySelector('input[name="age"]').disabled = true;
ブラウザ挙動 ── 送信・フォーカス・スタイル
- 送信時の扱い
- 値は form data に含まれず、
GET
クエリや POST
本文に現れない
- フォーカス
- キーボード Tab 移動不可。プログラム的
.focus()
も無効
- イベント
click
/ change
等の UI イベント発火しない(ただし stop ではなく non-bubble)
- UI 表示
- 既定でグレーアウト。
appearance
はブラウザ・OS テーマに依存
disabled と readonly の決定的な違い
特性 |
disabled |
readonly |
編集 |
不可(そもそも操作不能) |
不可(選択は可) |
フォーカス |
不可 |
可 |
送信 |
値は送信されない |
値は送信される |
適用対象 |
ほぼ全フォーム要素 |
テキスト系のみ (`<input type=text |
CSS :disabled 擬似クラスとスタイリング
button:disabled,
input:disabled {
opacity: 0.5;
cursor: not-allowed;
}
:enabled
と併用して動的テーマを構築可能。
- ブラウザ差異
- Safari は macOS テーマ優先で背景色が上書きできない場合あり。
-
- 回避策
appearance: none;
で OS スタイルを外す。
JavaScript での動的制御パターン
フォーム全体を ON/OFF
const form = document.querySelector('form');
form.elements.forEach(el => el.disabled = true);
バリデーションと連動
const btn = document.querySelector('button[type=submit]');
const email = document.querySelector('input[type=email]');
email.addEventListener('input', () => {
btn.disabled = !email.checkValidity();
});
Vue・React 例
<!-- Vue 3 -->
<button :disabled="!isValid">送信</button>
<!-- React -->
<button disabled={!isValid}>送信</button>
fieldset の一括無効化と例外
fieldset
に disabled
を付けると 子孫のすべて が無効化。
- 例外
- 同じ
fieldset
内で 最初の <legend>
は操作可能。
-
- ラジオボタン切り替え UI などで
legend
をクリック可能にしたい場合に配慮。
<fieldset disabled>
<legend>会員情報</legend>
<input name="name">
<input name="email">
</fieldset>
アクセシビリティ & ARIA での拡張
- ネイティブ控えめ
disabled
- OS による読み上げ:「利用できません」など自動対応
- カスタム Widget
aria-disabled="true"
- JavaScript でキーダウン抑制+フォーカス制御が必要
- 説明ラベル
aria-describedby
- 無効理由をスクリーンリーダーに伝える
<div role="button" aria-disabled="true" tabindex="0" aria-describedby="reason">
Download
</div>
<p id="reason" hidden>契約プランが Basic のため無効です</p>
バリデーション API との関係
disabled
要素は Constraint Validation 対象外
required
, pattern
, min/max
などは無視される。
.checkValidity()
しても常に true
。
- 送信を制御する 最終手段 として利用可能
- 「そもそも無効にしておけば検証させない」
よくある実装シナリオ
- ステップフォーム
- 現ステップが完了するまで「次へ」ボタンを無効化
- 価格プラン選択
- 無料プランでは高機能入力欄を無効化
- 同意チェックボックス
- 利用規約に同意するまで送信を無効化
- ネットワーク遅延
- 二重送信防止で Ajax 送信中にボタンを一時無効化
落とし穴・アンチパターン集
- ボタンが見た目だけ無効だがクリックできる
disabled
ではなく class="disabled"
だけ付与
- ネイティブ属性を必ず付与
- タブキーで飛ばせない → ユーザー困惑
disabled
はフォーカス不可
- 非活性でもタブ遷移を維持したい場合は
readonly
+ aria-disabled
- カスタム要素にそのまま
disabled
を付与
- 対象外なので無視
- CSS +
aria-disabled
+ JS でふるまいを再実装
ブラウザ互換性と仕様の歴史
- 1995年
- HTML 2.0 で初登場(
<input>
のみ)
- 1997年
- HTML 4.0 で
<button>
, <select>
等に拡大
- 2019年
- WHATWG HTML で
fieldset
・option
の仕様整理
- 現在
- 主要ブラウザは 100% サポート。EdgeHTML 時代のバグ(フォーカス喪失イベント)も解消
- 注意
- 仕様の更新は稀だが アクセシビリティ WG で議論が続くため、非ネイティブ UI では最新の ARIA 実装状況を確認すると安心。
主要フレームワークとの連携 Tips
- React
disabled
は真偽値。布値(文字列)を渡すと常に true
扱いに注意。
-
<button disabled={!canSubmit}>送信</button>
- Vue 3
:disabled
でバインド。オブジェクトスプレッドで一括制御可。
-
<input v-bind="{ disabled: !canEdit, readonly: canView }">
- Angular
formControlState
で .disable()
/ .enable()
を呼ぶと自動で UI も更新。
- Svelte
disabled={condition}
。Reactive 宣言と相性◎。
ベストプラクティスまとめ
- 可能な限りネイティブ
disabled
を使う
- セマンティクス・アクセシビリティが無料で付いてくる
- 視覚的だけでなく動作も無効化する
- CSS だけで “灰色表示” しても意味なし
- ユーザーに理由を示す
aria-describedby
+ ツールチップで「なぜ押せないか」説明
- 送信直前の非活性化
- 二重送信防止は古典かつ有効
- カスタム UI には
aria-disabled
- ボタン以外で「クリック不可」を示すときの必須知識
- 自動テストでは
.disabled
or :disabled
を assert
- 見た目チェックは脆弱
まとめ
disabled
属性は フォーム UX と アクセシビリティ を支える基本要素です。
ネイティブの挙動 を理解し、スタイリング・動的制御・ARIA 代替 を組み合わせれば、初学者でも“触れない”UIを安全に実装でき、上級者は仕様差異まで把握して堅牢なフォームを構築できます。
“無効化” は単なるグレーアウトではなく、相互作用の契約を切る宣言。
その重みを意識してこそ、ユーザーは迷わずフォームを使えるようになります。