操作した瞬間に設定が変わる「即時反映型」のON/OFFコントロール。スマートフォンのOSから持ち込まれた直感的なUIだが、「保存なしで即時適用される」という暗黙の契約をユーザーと結んでいる。
この記事を読むと、SwitchとCheckbox・Toggleの正確な使い分け、即時反映における安全設計、A11y(role="switch")要件が自分でできるようになります。
1. UI例(Preview / Live)
このスイッチは、デザインシステム GUNJO の Switch 実装(checked / onCheckedChange、label / description props、role="switch")です。操作した瞬間に反映される設定パネルで確認できます(右上 Code で編集可)。
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
操作した瞬間にシステムの状態を変更する即時反映型のON/OFFコントロール。見た目はスライド式のトグルで、スマートフォンのOS設定UIから広まった。
Checkboxとの違い:Checkboxは「フォームの一部として、送信ボタンを押すまで確定しない選択肢」。Switchは「操作した瞬間に設定が変わる即時コントロール」。保存ボタンが必要かどうかが判断基準。
Toggleとの違い:Toggleはエディタの書式設定ボタンのように「コンテンツへのスタイル適用」に使い、SwitchはOSやアプリの「システム設定の即時変更」に使う。副作用の重さと即時性が異なる。
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- アプリの設定画面で、操作した瞬間に設定が保存・反映されるON/OFFコントロール(通知設定・ダークモード・自動保存など)
- 保存ボタンなしで即時反映されることがユーザーに自明な文脈
- フォームの外側に配置される独立した設定項目
3.2 When NOT to use
- フォームの一部として、送信ボタンで一括確定する選択肢(Checkbox を使う)
- 「同意する」「利用規約に合意」など、意思確認を要する選択(Checkbox を使う)
- 操作後に確認ダイアログが必要になるほど重大な変更(AlertDialog を使う)
3.3 代替UI(Alternatives)
- フォーム内の選択肢 →
Checkbox - コンテンツへのスタイル適用切替 →
Toggle - 重大な設定変更(取り消し不可) →
AlertDialog→ 確認後にSwitch
4. 設計判断の核(Decision Principles)
「保存ボタンを押さなくても変わる」——その暗黙の契約を守れるときだけ Switch を使う。
判断の優先順位:① 即時反映か遅延確定か → ② 副作用の重さ → ③ role="switch" の付与
- Switch を使う = 「操作した瞬間に副作用が発生する」という約束をユーザーに与える。その約束を守れない実装なら Checkbox に変える
- 非同期処理(APIコール)が完了するまでの間は、Switch を Loading 状態にしてユーザーの連打を防ぐ
- ON/OFF の意味が「ラベルだけでは不明瞭」な場合は、ONラベル・OFFラベルを並記する(例:「有効 / 無効」)
- 副作用が取り返しのつかないほど重大な設定の場合は、Switch の前段に AlertDialog を挟んで確認を求める
5. 状態設計(States)
5.1 必須状態(Required)
- Default ON:青(またはブランドカラー)で塗りつぶし。ノブが右寄り
- Default OFF:グレーで塗りつぶし。ノブが左寄り
- Focus:キーボード操作時にフォーカスリングを表示(省略不可)
- Disabled:透明度を下げ
cursor-not-allowed。ラベルの色も薄くする
5.2 条件付き状態(Conditional)
- Loading:API処理中にノブをスピナー化し、操作を一時無効にする
- Error:API失敗時に元の状態に戻し、エラーメッセージをトーストやインラインで表示する
5.3 State Gallery
| 状態 | 必須 | 何を伝えるか |
|---|---|---|
| Default ON | ✅ | 現在この設定が有効であること |
| Default OFF | ✅ | 現在この設定が無効であること |
| Focus | ✅ | キーボードユーザーに今ここにいることを示す |
| Disabled | ✅ | この設定は現在変更できないこと |
| Loading | — | 設定変更をシステムが処理中で、完了まで待つ必要があること |
| Error | — | 設定変更が失敗し、元の状態に戻ったこと |
6. バリエーション設計(Variants)
Switch のバリアントは「見た目のサイズ」より「ラベルの配置と明示度」で設計する。
| バリアント | 目的 |
|---|---|
| Label Left | 設定項目名をSwitchの左に置く(一般的な設定行) |
| Label with Description | 設定名+補足テキスト+Switch の3点セット(意味が複雑な設定) |
| ON/OFF Inline Label | Switch内部または直隣に「ON」「OFF」文字を表示(意味が曖昧な場合) |
禁止パターン:ラベルなしのSwitch単体 → 何をON/OFFしているのか完全に不明になる。
7. パターン集(Good / Bad / How to fix)
7.0 よく崩れる設計パターン(3つ)
- Checkboxで即時反映:フォーム内のCheckboxを「保存なしで即時変更」として使うと、ユーザーが「これは保存されるのか?」と混乱する
- Loading状態の欠落:API処理中も Switch が操作可能なまま → 連打による不整合状態が発生する
- role="switch" の欠落:見た目がSwitchでも
roleがなければスクリーンリーダーは「ボタン」として読み上げ、ON/OFF状態を伝えられない
7.1 Bad(典型3つ)
- 設定フォームに Checkbox が並び、「保存する」ボタンなしで配置 → Switch にすべき or 保存ボタンが必要か不明
- Switch を操作してAPIが失敗したが、UIは ON のまま → ユーザーは設定が変わったと誤認する
<div>にCSSだけで Switch を再現しrole="switch"もaria-checkedもない → スクリーンリーダーが無視する
7.2 Good(対になる3つ)
- 即時反映の設定には Switch、フォームの一括確定には Checkbox と役割を分離する
- API処理中は Switch を Loading 状態(スピナー+disabled)にし、完了後に結果でUI状態を確定する
<button role="switch" aria-checked={isOn}>を使い、ON/OFF状態を DOM に正確に反映する
7.3 How to fix(手順)
- 「保存ボタンを押さずに即時変更が起きるか?」を確認 → Yes なら Switch、No なら Checkbox
- APIコールを伴う場合は Loading 状態を追加し、成功/失敗で UI 状態を確定するハンドリングを実装する
<button role="switch" aria-checked={checked}>で実装し、見た目の状態と ARIA 状態を常に同期する
7.4 GUNJO 実装で見る(Bad / Good)
同じ GUNJO の Switch を、ラベル関連付けの崩れた使い方と正しい使い方で対比。
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Keyboard
Tabでフォーカスでき、Spaceで状態を切り替えられること
Focus
- フォーカスリングは周囲と4.5:1以上のコントラストを持つこと
Screen Reader
role="switch"とaria-checkedを付与し、スクリーンリーダーが「スイッチ、オン/オフ」と読み上げられるようにする- ラベルが視覚的に分離している場合は
aria-labelledbyまたはaria-labelで関連付ける
<!-- 基本パターン -->
<button
role="switch"
aria-checked="true"
aria-label="プッシュ通知"
>
<!-- ノブのDOM -->
</button>
Touch / Pointer
- 最小タップ領域 44×44px 以上を確保する(Switchのトラック全体をタップ可能にする)
Contrast / Readability
- ON状態の背景色(青)とノブ(白)は3:1以上のコントラスト比を確保する(WCAG 1.4.11)
10. 実装メモ(Implementation Notes)
role="switch"は<input type="checkbox">でも代替できるが、見た目を完全にカスタマイズするには<button role="switch">の方が扱いやすい。ただし<input>の方がフォームとの統合が容易- Radix UI / shadcn の
Switchコンポーネントはrole="switch"とaria-checkedを自動管理し、さらにフォームライブラリ(react-hook-form 等)との統合も容易なため推奨 - iOS Safari では
role="switch"の読み上げが「スイッチ」と認識される。Androidは「チェックボックス、オン/オフ」と読む場合がある。クリティカルなA11y要件がある場合は実機テストを行う
11. 関連リンク
- 関連するUIデザイン原則: フィードバック (Feedback), 明瞭性と確実性 (Clarity & Certainty), アフォーダンス (Affordance)
- 用語集(定義): アクセシビリティ (Accessibility), アフォーダンス (Affordance)
- 関連するUIコンポーネント(横): Toggle(トグルボタン), Checkbox(チェックボックス), Button(ボタン)
12. まとめ
Switch の設計は「即時反映の約束を守れるか」という一問に尽きます。迷ったら 4. 設計判断の核 に戻り、「保存ボタンなしで変わるか?」を確認してください。即時反映するなら role="switch" と Loading 状態の実装が最低ライン。副作用が重大な場合は AlertDialog を前段に挟んで誤操作を防いでください。