Skip to content
fandhe-frontendcore v0.4.3
GitHub

Action Bar

複数選択(チェックボックス等)に対する一括操作を提示する画面下部固定の操作バーです。fandhe-frontend-headless-ui の action_bar mod が構造・アクセシビリティ(WAI-ARIA・キーボード操作)・表示状態(data-*)のみを提供する unstyled 部品であり、Themes 版と異なりスタイル(CSS)は一切持ちません。開閉状態は Disclosure を埋め込んだ状態機械が管理しますが、「選択操作から開閉状態を決定する」判断自体は呼び出し側アプリケーションの責務です。content は role="dialog"(非モーダル)で表され、開状態のときのみ data-expanded が付与されます。

スタイル済みの表示例は Action Bar を参照してください。

キーボード操作

キー対象効果
EscapeContentバーを閉じます(fandhe-frontend-wasm-full の OverlayKind::ActionBar が配線。data-close-on-escape="false" で opt-out できます)。
Tab / Shift+TabRoot 配下のボタンネイティブ button 要素間のフォーカス移動です。開いた瞬間にフォーカスが自動で移動することはありません(content は tabindex="-1" を固定で持ち、chakra-ui の autoFocus: false と同じ挙動です)。

参考サイトとの差分(イシュー #1647)

ark-ui・Radix Primitives のいずれにも ActionBar 相当のコンポーネントは存在しません。参照できるのは chakra-ui の ActionBar のみで、その実体は独自の状態機械を持たず Ark Popover(zag.js popover.connect)をそのまま再利用しています。このため本部品の属性仕様は zag.js popover の content/close-trigger の出力を基準にしています。

  • 是正した点: content の role を "toolbar"(矢印キーでの roving tabindex を伴わない不完全な適用でした)から "dialog"(非モーダル、aria-modal は付与しません)へ変更しました。あわせて開状態のときのみ data-expanded を付与し、tabindex="-1" を固定で付与するようにしました(呼び出し側が tabindex を指定していれば出力しません)。close-trigger は呼び出し側が aria-label を指定しておらず、かつ children が空(可視テキストを持たないアイコンのみボタン)のときに限り既定値 "close"(zag.js popover の translations.closeTrigger 既定値と同じ)を出力します。children に可視テキストがある場合は既定 aria-label を出力しません(WCAG 2.5.3 Label in Name 対策)。
  • 意図的に合わせていない点: root(hydration のルート要素として DOM を持つ必要があるため、DOM を描画しない参考サイトの Root とは異なります)・positioner(hidden 存在属性を pre-styled-ui が利用するため付与しており、参考サイトは素の div です)・separator(role="separator" + aria-orientation="vertical" をアクセシビリティ上の superset として維持しており、参考サイトは素の div です)。data-placement/data-side(配置バリエーション)はスタイル層(fandhe-frontend-pre-styled-ui)の責務としてスコープ外のままです(docs/policy/intentional-non-adoption.md §3.25 規則 2)。外側クリックでの閉鎖(closeOnInteractOutside)も既定で無効のまま opt-in 属性を持ちません — 選択操作用のチェックボックス等は ActionBar の外側(一覧側)に存在するため、外側クリックでの誤閉鎖を防ぐ安全側の判断です。

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

自前 CSS の最小例

Themes 版を使わず本部品を直接使う場合、data-scope/data-part 属性セレクタと data-state/data-expanded の有無で見た目を組み立てます。

CSS
[data-scope="action-bar"][data-part="positioner"] {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
}

[data-scope="action-bar"][data-part="content"][data-state="open"] {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}

[data-scope="action-bar"][data-part="close-trigger"]:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

Demo

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

Features

  • 複数選択操作バー(chakra-ui ActionBar 相当。実体は Ark Popover の再利用)。Root / Positioner / Content / SelectionTrigger / Separator / CloseTrigger の 6 anatomy パーツを持つ(action_bar.rs モジュール doc)。
  • 開閉は Disclosure を埋め込んだ状態機械 ActionBar が管理する。選択件数から open を自動導出する糖衣 API は持たず、「選択操作 → 開閉状態の決定」は呼び出し側の責務とする(action_bar.rs「選択件数から open を導出する糖衣 API は持たない」節)。
  • content に role="dialog"(非モーダル、aria-modal は付与しない)と aria-label(読み上げ用ラベル、呼び出し側が指定する必須引数)を固定付与する。参照基準(zag.js popover の content)に合わせイシュー #1647 で role="toolbar"(roving tabindex を伴わない不完全な適用だった)から是正した(**破壊的変更**、content 関数)。
  • content は開状態のときのみ data-expanded 存在属性を出力し、tabindex="-1" を固定付与する(chakra autoFocus: false に対応。開時にフォーカスを自動移動しない。呼び出し側 attrs に tabindex があれば出力しない、content 関数)。
  • close-trigger は呼び出し側 attrs に aria-label が無く、かつ children が空(可視テキストを持たないボタン)のときに限り既定値 "close"(zag.js popover の translations.closeTrigger 既定値、CLOSE_TRIGGER_ARIA_LABEL)を出力する(close_trigger 関数。children に可視テキストがあれば既定 aria-label は付与しない)。
  • closed のとき positioner/content の双方に hidden 存在属性を付与し、SSR/no-JS でも閉状態を表現する(positioner/content 関数)。
  • 参照基準に存在する data-placement/data-side(placement variant)は本実装のスコープ外(docs/policy/intentional-non-adoption.md §3.25 規則 2、装飾・レイアウト計測は headless-ui へ持ち込まない)。外側クリックでの閉鎖(closeOnInteractOutside)は既定 false のまま opt-in 属性を持たない(選択操作のチェックボックス等が ActionBar の外側に存在するため、誤閉鎖を防ぐ安全側の判断)。

Anatomy

root
  positioner
    content
      selection-trigger
      separator
      close-trigger

API Reference

Arguments

NameTypeDefaultDescription
root(state)OpenState—開閉状態(Open/Closed)。data-state へ反映される。
content(label)&str—role="dialog" の aria-label(選択操作バーの読み上げ名、必須引数)。
selection_triggerfn—type="button" を固定付与するボタンパーツ。選択件数テキストは呼び出し側が children で渡す。
close_trigger(attrs)Vec<(&str, &str)>—aria-label 未指定かつ children が空のときのみ既定値 "close" を出力する(CLOSE_TRIGGER_ARIA_LABEL)。呼び出し側が aria-label を指定するか children に可視テキストを渡せば上書き・不出力になる。

Data Attributes

PartAttributeObserved Values
contentdata-expanded(値なし)
contentdata-stateopen
positionerdata-stateopen
rootdata-stateopen

Examples

CloseTrigger のみの最小構成

SelectionTrigger/Separator を省き、Content 直下に CloseTrigger だけを配置した例です。

自前 CSS の最小例

data-scope / data-part 属性セレクタと :focus-visible 擬似クラスで見た目を組み立てる最小例です。headless-ui 自体はスタイルを持ちません。

CSS
[data-scope="action-bar"][data-part="positioner"] {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
}
[data-scope="action-bar"][data-part="content"][data-state="open"] {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}
[data-scope="action-bar"][data-part="close-trigger"]:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

Accessibility

Keyboard Interactions

KeyDescription
Escapecontent が開いている間、バーを閉じる(fandhe-frontend-wasm-full の OverlayKind::ActionBar が配線。data-close-on-escape="false" で opt-out 可能)。
Tab / Shift+Tabネイティブ要素(button)由来のフォーカス移動。開時に自動でフォーカスは移動しない(tabindex="-1"、chakra autoFocus: false に対応)。

WAI-ARIA

AttributeDescription
role="dialog"content に固定付与(非モーダル、aria-modal は付与しない)。aria-label とセットで出力される。参照基準(zag.js popover)に合わせイシュー #1647 で role="toolbar" から是正済み。
data-expandedcontent が開状態のときのみ出力される存在属性(zag.js popover の content と同じ語彙)。
aria-label="close"close-trigger の既定値。呼び出し側 attrs に aria-label が無く、かつ children が空(可視テキストを持たない)のときに限り出力される。呼び出し側が aria-label を指定するか children に可視テキストを渡せば出力されない。
role="separator" / aria-orientation="vertical"separator に固定付与(ActionBar のボタン列は横並びのため区切り線は縦向きになる。参照基準は素の div であり、a11y 上の superset として維持する意図的差分)。