UIXHERO
この記事は英語でも読めます。 Read the English version

Toggle Group(トグルグループ)

複数の選択肢を排他選択(単一選択)または複数選択できるボタングループUIコンポーネント。RadioとCheckboxとの使い分け・単一/複数選択の設計・ARIA rolegroupパターンの実装を解説する。

2026年3月3日
更新: 2026年9月3日
22
by Dengen Yosho(DGYS)

複数の選択肢を視覚的なボタングループとして並べ、排他選択(単一選択)または複数選択を提供するコンポーネント。テキストエディタのフォント装飾(B / I / U)・表示切り替え(グリッド / リスト)・フィルタータグの選択などで広く使われる。

この記事を読むと、Toggle GroupとRadio・CheckboxとTabs・Filterの使い分け・単一選択と複数選択のAPI設計・必ず1つ選択済みにする強制選択モード・ARIA rolegroup + aria-pressed パターンが自分でできるようになります。


1. UI例(Preview / Live)

実装で見る(GunjoUI)

この部品を、デザインシステム GUNJO の実装で確かめられます。

2. 定義(Definition)

複数の選択肢をボタングループとして並べ、単一選択(排他)または複数選択を提供するUIコンポーネント。フォームの <input type="radio"><input type="checkbox"> の「ボタン版」として機能する。role="group" でグループを意味論的にまとめ、各ボタンに aria-pressed で選択状態を伝える。

RadioとToggle Groupの違い:Radioはフォーム内の「値の送信」を目的とし、<fieldset> + <legend> で構造化する。Toggle Groupはフォーム外のUIの「状態制御」(表示切り替え・フィルター・テキスト装飾)を目的とし、role="group" + aria-pressed で実装する。

TabsとToggle Groupの違い:Tabsは「表示するパネルコンテンツを切り替える」——選択したタブに対応するコンテンツブロックが表示される。Toggle Groupは「UIの状態を制御する」——コンテンツブロックとの紐付けはなく、状態の値を管理するだけ。


3. 使い分け(When to use / When NOT to use)

3.1 When to use

  • 表示形式の切り替え(グリッド表示 / リスト表示 / テーブル表示)
  • テキストエディタのフォント装飾(太字 / イタリック / 下線)
  • フィルタータグ(複数選択可能なカテゴリフィルター)
  • 設定のオプション切り替え(サイズ: S / M / L、整列: 左 / 中央 / 右)

3.2 When NOT to use

  • フォームで値を送信する → Radio(単一)または Checkbox(複数)を使う
  • 選択肢が6個以上 → Select または Combobox を使う
  • コンテンツパネルの切り替え → Tabs を使う(aria-controls でパネルと紐付ける)

3.3 代替UI(Alternatives)

  • フォームの単一選択 → Radio Button
  • フォームの複数選択 → Checkbox
  • コンテンツ切り替え → Tabs
  • 多数の選択肢 → Select / Combobox

4. 設計判断の核(Decision Principles)

Toggle Groupの核は「単一選択 vs 複数選択」の明確な設計——どちらのモードかをUIの見た目と動作で一貫させる。排他選択なのに0件選択できてしまうと、ユーザーはどの状態が「デフォルト」か分からなくなる。

判断の優先順位:① 単一/複数選択モードの決定 → ② 強制選択(0件禁止)の要否 → ③ スタイリング → ④ AR実装

  • 単一選択は「必ず1つ選択済み」を強制する:表示形式の切り替えなど、「未選択」という状態が存在しないケースでは、選択済みのボタンを再クリックしても選択解除されないようにする(if (newValue === current) return;
  • 複数選択は0件を許容するかどうかを明示する:フィルタータグでは0件選択=「すべて表示」として機能させるのが自然。テキスト装飾では0件=「装飾なし」として許容する
  • グループ全体に role="group"aria-label を付与するrole="group" でスクリーンリーダーに「関連するボタンのグループ」として認識させる。aria-label で「テキスト揃え」「カテゴリフィルター」など目的を伝える
  • 各ボタンに aria-pressed を付与するaria-pressed="true" で選択中、aria-pressed="false" で非選択を伝える。aria-checked ではなく aria-pressed を使う(<input type="radio"> との意味論的な違いを保つ)

5. 状態設計(States)

5.1 必須状態(Required)

  • Default(非選択)aria-pressed="false"、未選択スタイル
  • Pressed(選択中)aria-pressed="true"、ハイライトスタイル

5.2 条件付き状態(Conditional)

  • Disabled(無効):グレーアウト、disabled 属性 または aria-disabled="true"
  • Hover / Focus:ホバーハイライト、フォーカスリング
状態必須何を伝えるか
Default(非選択)このオプションは現在選択されていない
Pressed(選択中)このオプションが現在選択されている
Disabledこの選択肢は現在使えない

6. バリエーション設計(Variants)

選択モードとスタイルの組み合わせで使い分ける。

バリアント選択モードスタイル使用例
コントロール単一・強制選択ピル型・色切り替え表示形式・ソート順
ボタングループ単一または複数ボーダー・色切り替えテキスト装飾・整列
フィルタータグ複数・0件許容ピル型・ラウンドカテゴリフィルター
アイコングループ単一または複数アイコンのみテキスト揃え・フォーマット

禁止パターン:Toggle Groupをフォームの送信値の管理に使う → <input type="radio"> / <input type="checkbox"> を使い、フォーム送信に正しく対応させる。


7. パターン集(Good / Bad / How to fix)

7.0 よく崩れる設計パターン(3つ)

  • 単一選択で0件選択が可能:「グリッド表示」「リスト表示」の切り替えで、選択済みを再クリックすると両方が非選択になり、どの表示になっているか分からなくなる
  • aria-pressed がない:スクリーンリーダーがどのボタンが選択中かを伝えられず、視覚に頼れないユーザーが選択状態を把握できない
  • アイコンのみで aria-label がない:「B」「I」「U」のみのボタングループで、スクリーンリーダーが「B ボタン」としか読み上げず「太字」を伝えられない

7.1 Bad(典型3つ)

  • onClick={() => setSelected(val === selected ? null : val)} で0件選択を許容し、表示形式が「未選択」という不正状態になる
  • <button className={selected === val ? 'active' : ''}> のスタイル切り替えのみで aria-pressed がない
  • <button>B</button> だけで aria-label="太字"title="太字" も付与されていない

7.2 Good(対になる3つ)

  • onClick={() => { if (val !== selected) setSelected(val); }} で再クリック時の選択解除を防ぎ、常に1つが選択済みの状態を保つ
  • 各ボタンに aria-pressed={selected === val} を付与し、スクリーンリーダーに「押されています」「押されていません」を伝える
  • アイコンのみのボタンには aria-label="太字"title="太字" の両方を付与し、スクリーンリーダーとツールチップの両方に対応する

7.3 How to fix(手順)

  1. 単一選択:onClickif (val === current) return; を追加して選択解除を防ぐ
  2. 各ボタンに aria-pressed={value === item.value} を追加する
  3. グループ全体のラッパーに role="group"aria-label="[グループの目的]" を追加する
  4. アイコンのみのボタンに aria-label を追加する

8. ルール(Must / Better)

Must(守らないと壊れる)

Better(品質が跳ねる)


9. アクセシビリティ要件(必須)

Keyboard

  • Tab でグループにフォーカス
  • (または )で項目間を移動する(roving tabindex: フォーカス中の項目のみ tabIndex={0}、それ以外は tabIndex={-1}
  • Space / Enter で選択/解除

Focus

  • フォーカスリングをすべてのボタンに表示する
  • roving tabindex を使うと「Tabでグループ全体→矢印で項目移動」の自然なキーボード体験になる

Screen Reader

<div role="group" aria-label="テキスト揃え">
  <button aria-pressed="true" aria-label="左揃え" tabindex="0">≡</button>
  <button aria-pressed="false" aria-label="中央揃え" tabindex="-1">☰</button>
  <button aria-pressed="false" aria-label="右揃え" tabindex="-1">≡</button>
</div>

Touch / Pointer

  • ボタンのは最低44×44px
  • ピル型の小さいフィルタータグでは min-height: 44px + 十分な水平パディングで確保する

10. 実装メモ(Implementation Notes)

  • shadcn/ui の ToggleGroup@radix-ui/react-toggle-group ベースで、type="single" / type="multiple" の切り替え・aria-pressed・roving tabindex がすべて実装済み
  • roving tabindex の自前実装は useRef で全ボタンの参照を保持し、onKeyDownArrowRight/ArrowLeft を捕捉してフォーカスを移動する。実装コストが高いため shadcn/ui の使用を強く推奨
  • フィルタータグとして使う場合、選択状態をURLのクエリパラメータ(?tags=ui-components,glossary)に永続化すると、ページリロード・ブラウザバックでフィルター状態が復元される

11. 関連リンク


12. まとめ

Toggle Groupの設計で最重要なのは「単一 vs 複数選択モードの明確化」と「aria-pressed の実装」です。迷ったら 4. 設計判断の核 に戻り、単一選択での強制選択・role="group" + aria-labelaria-pressed の3点を確認してください。shadcn/ui の ToggleGroup を使えばroving tabindex・aria-pressed・単一/複数選択モードは自動的に実装されます。RadioやCheckboxとの混同に注意——フォームへの値送信が目的なら <input type="radio"> / <input type="checkbox"> を使い、UIの状態制御が目的なら Toggle Group を使うという使い分けが正しい選択です。

更新のお知らせ

サイトに載せていない実例や、新しい記事のお知らせはこちらで出しています。

読んだ内容を、自分の画面に当てるとき

UIXHEROは、記事を書くほかに、画面の検品・判定、デザインシステムの構築、実装と改善の伴走を受けています。何を頼めばいいか決まっていない段階の相談も、同じ窓口で受けます。

UIXHEROに頼めることを見る

※ 記事の内容についての質問や、書いてほしいテーマの要望も同じ窓口で受けています

記事をシェア

メールでお知らせを受け取る

最終更新: 2026年9月3日

この記事を書いた人

Dengen Yosho(DGYS)

Dengen Yosho(DGYS)

UI/UXデザイナー兼デザインエンジニア デザイン歴25年以上 情報設計〜UIデザイン〜React/TypeScriptによる実装までを一気通貫で担当 大手企業のDXプロジェクトや決済アプリ領域で、デザインリードとして改善と構築を経験 現在はフリーランスとして、プロダクトのUI/UX改善とデザインシステム構築を支援 長年の実務の中で感じてきたのは、 「良いUI」はセンスではなく、再現可能な判断の積み重ねであるということ UIXHEROは、 心理学や行動科学の知見を、現場で使える設計言語に翻訳するための場所 関心領域は「ユーザーの行動が変わるUI」 人の認知・注意・意思決定の構造を理解し、 “なぜそのUIが機能するのか”を言語化することを目指している

あわせて読みたい

この記事に関連する記事をご紹介します

Bar Chart(棒グラフ)

カテゴリごとの量を棒の長さで比べるチャート。ゼロ基線の扱い、並び順、縦横の選び方、しきい値の見せ方という設計判断と、色だけに頼らないアクセシビリティ要件を解説する。

2026年8月27日
18

Donut Chart(ドーナツチャート)

中央をくり抜いた円で構成比を示すチャート。中央に置く値の選び方、円グラフとの使い分け、リングの太さ、凡例の作りという設計判断と、色だけに頼らないアクセシビリティ要件を解説する。

2026年8月27日
17

Gauge Chart(ゲージチャート)

1つの値を範囲の中に置いて示す半円のチャート。範囲の両端に意味があるかという条件、しきい値の帯の設計、色だけで良否を伝えない書き方という設計判断とアクセシビリティ要件を解説する。

2026年8月27日
16

もっと深く知りたいですか?

ここに掲載されていないトピックについても、リクエストがあれば解説記事を追加します。 わかりにくい点や、具体的な事例について知りたいことがあれば教えてください。

リクエストを送る