HTML

It’s an attribute that completely removes a form control from user interaction and form submission, effectively disabling it.

disabled 属性

概要:disabled は何をする属性か

機能
フォーム“コントロール”をユーザー操作から 完全に 無効化し、フォーム送信時にも値を送らせない。
無効化されたコントロールは、事実上 DOM 上の “装飾” に変わる。
仕様位置
典型例
送信ボタンを条件達成まで押させない、購読プランに応じて入力欄を非活性化。

HTML

<button type="submit" disabled>送信</button>

基本構文と適用可能要素

入力系
<input>, <textarea>, <select>
type 不問。テキスト・チェックボックス等すべて
選択系
<option>, <optgroup>
子要素にも波及
ボタン系
<button>
フォーム部品以外
直接は不可。代替は aria-disabled を使用

静的指定(HTML側)

HTML

<input type="number" name="age" disabled>

動的指定(JS側)

JavaScript

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 擬似クラスとスタイリング

CSS

button:disabled,
input:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

:enabled と併用して動的テーマを構築可能。

ブラウザ差異
Safari は macOS テーマ優先で背景色が上書きできない場合あり。
回避策
appearance: none; で OS スタイルを外す。

JavaScript での動的制御パターン

フォーム全体を ON/OFF

JavaScript

const form = document.querySelector('form');
form.elements.forEach(el => el.disabled = true);

バリデーションと連動

JavaScript

const btn = document.querySelector('button[type=submit]');
const email = document.querySelector('input[type=email]');

email.addEventListener('input', () => {
	btn.disabled = !email.checkValidity();
});

Vue・React 例

HTML

<!-- Vue 3 -->
<button :disabled="!isValid">送信</button>

HTML

<!-- React -->
<button disabled={!isValid}>送信</button>

fieldset の一括無効化と例外

fieldsetdisabled を付けると 子孫のすべて が無効化。

例外
同じ fieldset 内で 最初の <legend> は操作可能。

HTML

<fieldset disabled>
	<legend>会員情報</legend>
	<input name="name">
	<input name="email">
</fieldset>

アクセシビリティ & ARIA での拡張

ネイティブ控えめ
disabled
OS による読み上げ:「利用できません」など自動対応
カスタム Widget
aria-disabled="true"
JavaScript でキーダウン抑制+フォーカス制御が必要
説明ラベル
aria-describedby
無効理由をスクリーンリーダーに伝える

HTML

<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 で fieldsetoption の仕様整理
現在
主要ブラウザは 100% サポート。EdgeHTML 時代のバグ(フォーカス喪失イベント)も解消
注意
仕様の更新は稀だが アクセシビリティ WG で議論が続くため、非ネイティブ UI では最新の ARIA 実装状況を確認すると安心。

主要フレームワークとの連携 Tips

React
disabled は真偽値。布値(文字列)を渡すと常に true 扱いに注意。

HTML

<button disabled={!canSubmit}>送信</button>
Vue 3
:disabled でバインド。オブジェクトスプレッドで一括制御可。

HTML

<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を安全に実装でき、上級者は仕様差異まで把握して堅牢なフォームを構築できます。

“無効化” は単なるグレーアウトではなく、相互作用の契約を切る宣言。

その重みを意識してこそ、ユーザーは迷わずフォームを使えるようになります。