トグルボタングループ
component押すと「選ばれた状態」が残るボタンを並べ、その場で表示や設定を切り替えます。1 つ選ぶと他が外れる単一選択(一覧 / グリッドなど表示形式の切り替え)と、それぞれ独立に ON / OFF する複数選択(太字 / 斜体などの書式)の 2 つのモードがあります。中身は ボタン と アイコンボタン の neutral ghost を薄い帯の中に並べるセグメント型で、選ばれたものだけが白いセグメントになります。選択状態は各ボタンの aria-pressed で示します。
単一選択
同じ内容の見え方を 1 つ選んで切り替える。data-selection="single" を目印に、押したボタンだけを aria-pressed="true" にする(選択中を押し直しても外さない)
<div class="toggle-btn-group" role="group" aria-label="表示形式" data-selection="single"> <button type="button" class="btn btn-md btn-neutral btn-ghost" aria-pressed="true">一覧</button> <button type="button" class="btn btn-md btn-neutral btn-ghost" aria-pressed="false">グリッド</button> <button type="button" class="btn btn-md btn-neutral btn-ghost" aria-pressed="false">ボード</button> </div>
複数選択
書式や表示オプションをそれぞれ独立に ON / OFF する。data-selection="multiple" で、押したボタンの aria-pressed を反転する(0 個選択も可)
<div class="toggle-btn-group" role="group" aria-label="文字の書式" data-selection="multiple"> <button type="button" class="icon-btn icon-btn-md icon-btn-neutral icon-btn-ghost" aria-pressed="true" aria-label="太字"> <svg class="icon icon-lg" aria-hidden="true"><use href="./icons.svg#lucide-bold"></use></svg> </button> … </div>
アイコンだけの単一選択
狭い場所の表示切り替えは icon-btn を並べ、それぞれに選択肢名の aria-label を付ける。見える名前も要るならボタンを ツールチップ で包む
<div class="toggle-btn-group" role="group" aria-label="表示形式" data-selection="single"> <span class="tooltip"> <button type="button" class="icon-btn icon-btn-md icon-btn-neutral icon-btn-ghost" aria-pressed="true" aria-label="一覧" aria-describedby="tip-list"> <svg class="icon icon-lg" aria-hidden="true"><use href="./icons.svg#lucide-list"></use></svg> </button> <span class="tooltip-content" id="tip-list" role="tooltip">1 行に 1 件ずつ表示</span> </span> … </div>
サイズ
中のボタンのサイズ(btn-{sm,md,lg} / icon-btn-{sm,md,lg})がそのままグループの高さになる。1 つのグループの中でサイズを混ぜない
縦並び
toggle-btn-group-vertical を足すと縦に積み、ボタン幅を最も長いものにそろえる。サイドパネルの表示オプションや縦のツールバーに使う
単一選択
複数選択
<div class="toggle-btn-group toggle-btn-group-vertical" role="group" aria-label="表示形式" data-selection="single"> <button type="button" class="btn btn-md btn-neutral btn-ghost" aria-pressed="false">一覧</button> … </div>
状態
選択は白いセグメント(枠 stroke-high)と文字の濃さ(fg/low → fg/high)の 2 つで示す。影は付けない。hover / focus は is-hover-preview / is-focus-preview の見本
機能
このコンポーネントの用途
選ばれた状態を持つボタンを並べ、その場で表示や設定を切り替える。
単一選択 = 同じ内容の見え方の切替(一覧 / グリッド / ボード、並び順 等)。
複数選択 = 独立した書式・表示オプションの ON/OFF(太字 / 斜体、補助線の表示 等)。
複数選択は filter-chip と仕組み(aria-pressed の独立トグル)が同じ。見分け方は
「押して一覧の件数(絞り込みの結果)が変わるか」: 変わるなら filter-chip、変わらず見た目・書式・
重ねて表示する情報(地図の駅表示など)だけが変わるなら toggle-btn-group。
表示する中身(パネル)そのものを切り替えるなら tab、一覧の絞り込みは filter-chip(複数)/ tab(件数付きの単一)、
フォームの入力値は radio / checkbox、単独の設定の ON/OFF は switch、選択状態を持たない操作の並びは btn-group。
使用法
推奨される使い方と、やりがちな NG パターン
OK
- ✓同じ内容の見え方を 2〜5 個から 1 つ選んで切り替える(data-selection="single"。例: 一覧 / グリッド / ボード)。
- ✓書式や表示オプションを独立に ON/OFF する(data-selection="multiple"。例: 太字 / 斜体 / 下線)。
- ✓中は btn-neutral btn-ghost(アイコンだけなら icon-btn-neutral icon-btn-ghost)で、同じ種類・サイズに揃える。
- ✓role="group" と aria-label でグループに名前を付ける(何を切り替えるか。例: 「表示形式」)。
- ✓選択状態は各ボタンの aria-pressed="true|false"。単一選択は常にちょうど 1 つを true にし、 選択中のボタンをもう一度押しても外さない。
- ✓アイコンだけのボタンはそれぞれ aria-label で選択肢の名前を付ける。見える名前も要るなら ボタンを tooltip で包む(包んだボタンにもグループの見た目が当たる)。
NG
- ✕表示する中身(別の情報)を切り替えるのに使わない → tab(tabpanel で中身を出し分ける)。
- ✕一覧の絞り込みに使わない → 複数同時の絞り込みは filter-chip、件数付きの 1 つ選択は tab。
- ✕フォームで送信する値の選択に使わない → radio(単一)/ checkbox(複数)。
- ✕実行するだけの操作(コピー / 貼り付け 等)を並べない → 選択状態が無いなら btn-group。
- ✕選択を背景色やクラスだけで示さない → aria-pressed を付ける(見た目も aria-pressed から決まる)。
- ✕単一選択で 0 個選択の状態を作らない → 何が表示されているか分からなくなる。
- ✕solid / outline のボタンや theme・サイズの違うボタンを混ぜない → 選択中のセグメントと区別できない。
- ✕6 個以上並べない → 選択肢が多いなら select。
- ✕選んだ瞬間にページ遷移・送信しない → その場で表示を切り替える部品(遷移は link / tab / menu)。
見え方を変えるならトグル、中身を変えるならタブ
用途の使い分け同じ案件の一覧を、行・カード・地図のどれで見るかを選ぶ。中身は変わらず、見え方だけが変わる。
<div class="toggle-btn-group" role="group" aria-label="表示形式" data-selection="single"> <button class="btn btn-md btn-neutral btn-ghost" aria-pressed="true">一覧</button>… </div>
概要・財務情報・担当者は別々の情報。表示する中身(パネル)を切り替えるなら タブ(tabpanel で出し分ける)。
<!-- 別の情報の出し分けに toggle-btn-group を使わない → role="tablist" のタブ --> <div class="toggle-btn-group"><button aria-pressed="true">概要</button>…</div>
一覧の絞り込みには使わない
用途の使い分け案件を状態で絞り込むなら フィルターチップ。件数が見え、何件に絞られるかが分かる。
<button type="button" class="filter-chip" aria-pressed="true">…公開中…12件…</button>
トグルボタンは見え方や書式の切り替え用。絞り込みに使うと件数を出せず、他の絞り込みとの組み合わせ方も伝わらない。
<!-- 一覧の絞り込みに toggle-btn-group を使わない → filter-chip / tab --> <div class="toggle-btn-group" aria-label="状態"><button aria-pressed="true">公開中</button>…</div>
単一選択は常に 1 つを選んでおく
状態の一貫性初期表示から 1 つを選んでおき、選択中を押し直しても外さない。いまどの並びで見ているかが常に分かる。
<button … aria-pressed="true">新着順</button> <button … aria-pressed="false">更新順</button>
どれも選ばれていないと、いまの並びが何なのか分からない。
<!-- 単一選択で全部 false にしない --> <button … aria-pressed="false">新着順</button> <button … aria-pressed="false">更新順</button>
トグルボタングループのアクセシビリティ
中はネイティブの <button> のままで、選択状態は各ボタンの aria-pressed、グループ名は role="group" + aria-label で伝えます。見た目は aria-pressed から決まるので、状態と表示がずれません。WCAG 2.2 全基準は アクセシビリティ ページを参照。
期待される配慮
Presentation / Adaptability / Interaction / Assistive Technology
選択は白いセグメントと文字の濃さ(fg/low → fg/high)の 2 つで示す。白と帯(neutral/50)の差はごく小さいため、文字の濃さの差(3.75:1)で色に頼らず区別できるようにしている。
並べる数は 2〜5 個に抑え、320px 幅でも 1 行に収める。収まらないならアイコンだけにするか select にする。
各ボタンが Tab で止まり、Enter / Space で切り替える。切り替えはその場の表示だけを変え、ページ遷移や送信を起こさない。
グループ名(「表示形式、グループ」)に続いて「一覧、切り替えボタン、押されています」のように、各ボタンの名前と押下状態が読まれる。
DS が担保する機能
追加実装なしで満たされる
- ✓選択中の見た目は
aria-pressed="true"から決まる(クラスで別に管理しないので、状態と表示がずれない) - ✓非選択の文字 fg/low は帯(neutral/50)の上で 4.55:1、hover(白)で 4.76:1。選択中の文字 fg/high は白いセグメントの上で 17.9:1
- ✓強制カラーモードでは選択中のボタンを Highlight で塗り、非選択との区別を保つ
- ✓中はネイティブ
<button>のまま。フォーカスリング(info/600)とターゲット最小 24px は btn / icon-btn のとおり
実装時の必須対応
プロダクト側で担保する
- !グループに
role="group"とaria-label(何を切り替えるか)を付ける - !押されたら
aria-pressedを書き換える。単一選択は押したボタンを true・他を false にし、選択中を押し直しても外さない - !アイコンだけのボタンには選択肢名の
aria-labelを付け、SVG はaria-hidden="true"。「一覧(選択中)」のように状態を名前に含めない
テスト方法
スクリーンリーダー / キーボード / 自動チェック
- SRグループ名と、各ボタンの名前・押下状態(押されています / 押されていません)が読まれる。切り替えると状態の読み上げも変わる
- キーTab で各ボタンに止まり、Space で切り替わる。単一選択は常に 1 つだけが選択中になる
- 自動axe / Lighthouse でボタンの名前(icon-btn の aria-label)とコントラストを確認
選択状態は aria-pressed で伝える
達成基準:WCAG 4.1.2 名前(name)・役割(role)及び値(value)「太字、切り替えボタン、押されています」と、名前と状態が別々に読まれる。
<button class="icon-btn …" aria-pressed="true" aria-label="太字">…</button>
クラスや名前の文言で状態を表すと、支援技術には「切り替えボタン」だと伝わらず、白いセグメントにもならない。
<!-- 状態をクラスや aria-label の文言で表さない --> <button class="icon-btn … is-selected" aria-label="太字(選択中)">…</button>