フォーム・入力

チェックボックス

解説あり

Checkbox

オン/オフの選択。中間状態(mixed)を含むチェックボックスの扱いも。

チェックボックスとは?

チェックボックスは、項目を「オン / オフ」で選ぶ UI です。 設定の有効化、利用規約への同意、複数項目の選択(通知の種類、絞り込み条件など)でよく使われます。

さらに「すべて選択」のような親チェックボックスでは、 子が「全部オン」「全部オフ」だけでなく「一部だけオン」という第3の状態 (中間状態 / mixed)を表す必要があります。ここが見落とされがちなポイントです。

なぜアクセシビリティが大事なの?

最短ルートはネイティブの <input type="checkbox"><label> と結びつけること。中間状態は indeterminate を使います。

ライブデモ(推奨実装)

「すべて選択」と3つの子チェックボックスです。子を一部だけオンにすると、親が中間状態(チェックでもなく空でもない見た目)になります。

アクセシブルなチェックボックス(すべて選択つき)
受け取る通知

試してみよう:Tab で各チェックボックスへ → Space でオン/オフ。子を1つだけオンにすると親が中間状態に、全部オンにすると親もオンになります。

ポイント

中間状態のとき、スクリーンリーダーは「すべて選択」を 「一部選択 / mixed(半選択)」と読み上げます。これはindeterminate = true を設定すると、ブラウザが自動的にaria-checked="mixed" として支援技術へ伝えてくれるためです。

キーボード操作

キー動作必須/任意
Tab次のチェックボックスへフォーカス移動必須
Spaceフォーカス中のチェックボックスをオン/オフ必須

補足

Space での切り替えは <input type="checkbox"> を使うだけで自動的に得られます。自分でキー処理を書く必要はありません。

必要な WAI-ARIA / ロール

付ける場所属性 / ロール意味
入力欄<input type="checkbox">ネイティブの checkbox ロール・状態・キーボード操作がすべて自動で付く。
ラベル<label>(input を内包 or for で関連付け)チェックボックスの「名前」になる。ラベルのクリックでもトグルできる。
親(すべて選択)indeterminate = true(JSプロパティ)一部だけ選択の中間状態。aria-checked="mixed" として自動で伝わる。
グループ<fieldset> + <legend>関連するチェックボックスをまとめ、グループ名を与える(任意・推奨)。

補足

indeterminateHTML属性ではなく JavaScript のプロパティです (el.indeterminate = true)。見た目が中間でも、内部の checked 値はtrue/false のままなので、送信値の扱いに注意します。

実装:推奨パターン(Good)

良い例 / 推奨

ネイティブの <input type="checkbox"><label> と関連付け、親は indeterminate で中間状態を表します。

マークアップ:

<fieldset>
  <legend>受け取る通知</legend>

  <!-- 親:すべて選択(中間状態は indeterminate で表現) -->
  <label>
    <input type="checkbox" id="cb-all"> すべて選択
  </label>

  <!-- 子:ネイティブの input + label を関連付け(Space でトグル) -->
  <label><input type="checkbox" class="cb-child"> メール</label>
  <label><input type="checkbox" class="cb-child"> SMS</label>
  <label><input type="checkbox" class="cb-child"> アプリ通知</label>
</fieldset>

「すべて選択」と中間状態の同期:

const all = document.getElementById('cb-all');
const children = document.querySelectorAll('.cb-child');

// 親 → 子:まとめて切り替える
all.addEventListener('change', () => {
  children.forEach((c) => { c.checked = all.checked; });
  all.indeterminate = false; // チェックが揃ったので中間状態を解除
});

// 子 → 親:全部 / 一部 / ゼロで親の状態を出し分ける
children.forEach((c) => c.addEventListener('change', () => {
  const checked = [...children].filter((x) => x.checked).length;
  all.checked = checked === children.length;                     // 全部 → on
  all.indeterminate = checked > 0 && checked < children.length;  // 一部 → mixed
}));

アンチパターン(Bad)

下は <div> で作った「見た目だけ」のチェックボックスです。マウスでは切り替わりますが、キーボードでは操作できず、状態も読み上げられません。

div で作った壊れたチェックボックス
メール
SMS
アプリ通知

試してみよう:Tab を押してもフォーカスが当たりません。スクリーンリーダーでは「チェックボックス」とも「オン/オフ」とも伝わりません。

<!-- ❌ アンチパターン:div で作った"チェックボックス風" -->
<div class="checkbox" onclick="this.classList.toggle('on')">
  <span class="box"></span> メール
</div>

悪い例 / 避ける

この実装の問題点:

  • キーボードで操作できないdiv はフォーカスを受け取れない。
  • 役割が伝わらない — 「チェックボックス」だと認識されない。
  • 状態が伝わらない — オン/オフ(や中間状態)が読み上げられない。
  • ラベル未関連 — 文字をクリックしても切り替わらず、名前も結びつかない。

実装チェックリスト


原文(英語):Checkbox Pattern — W3C APG(新しいタブで開きます)