Skip to content
fandhe-frontendcore v0.4.3
GitHub

Toggle Group

複数の押下可能なボタンをグループ化する unstyled 部品です。「高々 1 項目が押下される」状態機械(常時 deselectable)を提供し、各項目は独立した Toggle の集合として振る舞います。各 item は root と同じ orientation が Some のときに data-orientation を持ち、ToggleGroupProps::roving_focus(既定 false)を有効にすると SSR 側から roving tabindex を opt-in で出力できます(イシュー #1630)。

Themes 版(fandhe-frontend-pre-styled-ui)はこの構造へ既定 CSS を追加するだけの薄いラッパーであり、CSS は持ちません。スタイル済みの表示例は Toggle Group を参照してください。

関連 API: fandhe-frontend-headless-ui API

Demo

枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。

Features

  • Root(<div role="group">)/Item(<button type="button">)の 2 anatomy パーツと、「高々 1 項目が押下される」状態機械 ToggleGroup(single モード、常時 deselectable)を提供する。
  • 各 item は単体の crate::toggle::root と同じ aria-pressed/data-state(on/off)語彙を持つ(ToggleGroup の各項目は独立した Toggle の集合という ark-ui の位置付け)。
  • root/item は共通の ToggleGroupProps(disabled/orientation/roving_focus)を受け取る。orientation が Some のときのみ両パーツへ data-orientation を付与する(イシュー #1630 で item にも追加。role="group" は WAI-ARIA 上 aria-orientation を許可されていないため aria-orientation は付与しない)。
  • props.disabled は root の data-disabled に加えて全 item へも伝播する(item 個別の disabled との論理和。ark-ui/Radix の Root disabled が全 item を無効化する契約に合わせた、イシュー #1630 の是正)。
  • labelled_by が Some のときのみ aria-labelledby を付与する(名前なしの関連付けを作らない方針)。
  • ToggleGroupProps::roving_focus(既定 false)を true にすると、item の focused 引数に応じて tabindex="0"/"-1"(roving tabindex)を SSR 側から出力できる(イシュー #1630 opt-in。既定 false は no-JS でも全 item が Tab で到達可能なままにするため)。矢印キーによる実際のフォーカス移動 DOM 配線は fandhe-frontend-wasm-full の keynav が担い、本コンポーネント自体のスコープ外(下記 Keyboard 節参照)。
  • 呼び出し側 attrs からの tabindex/data-value/aria-pressed/data-orientation 等の偽装は fail-closed に除去する(イシュー #1630)。

Anatomy

root
  item

API Reference

Arguments

NameTypeDefaultDescription
props&ToggleGroupProps&ToggleGroupProps::default()disabled/orientation/roving_focus の 3 フィールドを持つグループ状態束。root/item の双方が参照する(イシュー #1630)。
labelled_byOption<&str>NoneSome のときのみ aria-labelledby を付与する。
pressed (item)boolfalse各 item の押下状態。data-state(on/off)・aria-pressed・data-pressed へ反映する。
focused (item)boolfalseprops.roving_focus が true のときのみ tabindex="0"/"-1" へ反映する(false のときは無視され tabindex を出力しない)。
disabled (item)boolfalse各 item 個別の無効化状態。props.disabled との論理和が実効値になる。
value (item)&str(必須)data-value としてそのまま出力する項目値(既定エスケープ経由)。

Data Attributes

PartAttributeObserved Values
itemdata-disabled(値なし)
itemdata-orientationvertical
itemdata-pressed(値なし)
itemdata-stateoff, on
itemdata-valuebold, bottom, center, italic, left, right, top
rootdata-disabled(値なし)
rootdata-orientationvertical

Examples

縦方向 + ラベル関連付け

props.orientation に Some(Orientation::Vertical)、labelled_by に Some("...") を渡すと data-orientation="vertical"(root/item 双方)と aria-labelledby が付与されます。

roving tabindex(opt-in)

ToggleGroupProps::roving_focus = true と item の focused 引数で、SSR 側から roving tabindex の初期状態を出力する例です。

roving_focus = true を渡すと、focused (第 3 引数) に応じて item が tabindex="0"/"-1" を出力します(既定は false)。矢印キーでの実際のフォーカス移動は fandhe-frontend-wasm-full の keynav が担うため、JS なしのこの静的例では center 以外はタブ順から外れたままです。

自前 CSS の最小例

headless-ui はスタイルレスであるため、root/item の data-* 属性セレクタで見た目を組み立てます。

利用者が data-scope / data-part / data-state / data-orientation / data-disabled 属性セレクタで自前 CSS を当てる最小例です。headless-ui 自体はスタイルを持ちません。

CSS
[data-scope="toggle-group"][data-part="item"][data-state="on"] {
  background: #2563eb;
  color: #fff;
}
[data-scope="toggle-group"][data-part="item"][data-disabled] {
  opacity: 0.5;
}
[data-scope="toggle-group"][data-part="root"][data-orientation="vertical"] {
  flex-direction: column;
}

Accessibility

Keyboard Interactions

KeyDescription
Tabroving_focus = false(既定)のときは全 item がネイティブなタブ順で到達可能。roving_focus = true のときは focused な 1 item のみが Tab ストップになる(roving tabindex、矢印キー押下後は fandhe-frontend-wasm-full の keynav が押下位置へ収束させる)。
Space / Enter各 item はネイティブ <button type="button"> であり、押下操作はブラウザ既定動作で成立する(MAPPING_TABLE の toggle-group/item → "toggle" 行が dispatch へ接続する)。
ArrowLeft / ArrowRight水平方向(data-orientation が None/"horizontal")のフォーカス移動。fandhe-frontend-wasm-full の keynav::toggle_group_next_index(radio_next_index 共有)が実装し、常時循環・disabled item をスキップする。
ArrowUp / ArrowDown垂直方向(data-orientation が "vertical")のフォーカス移動。data-orientation が欠落(None)のときは水平・垂直いずれの矢印キーも受理する(両軸受理、モジュール doc「意図的に合わせなかった点」参照)。
Home / End先頭/末尾の非 disabled item へフォーカス移動する(orientation 非依存、keynav::toggle_group_next_index 実装)。

WAI-ARIA

AttributeDescription
roleroot へ "group" を固定付与する。
aria-pressed各 item へ現在の押下状態を付与する。