Skip to content
fandhe-frontendcore v0.4.3
GitHub

Menubar

複数の Menu を水平(または垂直)に並べたアプリケーションメニューバーです。fandhe-frontend-headless-ui の menubar mod は Root / Menu / Trigger / Positioner / Content / Arrow / ArrowTip / Item / ItemText / ItemIndicator / ItemGroup / ItemGroupLabel / Separator / SubTrigger / SubContent / CheckboxItem / RadioItemGroup / RadioItem の 18 anatomy パーツを提供する unstyled 部品であり、Themes 版と異なりスタイル(CSS)は一切持ちません(イシュー #1652 で Radix Primitives Menubar と参照突合し、11 → 18 パーツへ拡充しました)。開いている Menu を跨いだ左右移動の状態遷移 API(MenubarAction)を持ちます。矢印キー・Home/End・typeahead の実 DOM 配線は fandhe-frontend-wasm-full が担います。

キーボード操作

キー対象効果
ArrowRight / ArrowLeft(垂直配置は ArrowDown / ArrowUp)Trigger隣の Trigger へフォーカスを移動します。ある Menu が開いていれば、開く Menu もフォーカス移動に追随します(open-follows-focus)。
ArrowDown / Enter / SpaceTrigger(closed)Menu を開き、先頭の非 disabled 項目を highlight します。
ArrowUpTrigger(closed)Menu を開き、末尾の非 disabled 項目を highlight します。
ArrowDown / ArrowUp / Home / EndContent(open)highlight 中の項目を次/前/先頭/末尾の非 disabled 項目へ移動します(CheckboxItem/RadioItem も対象)。
Enter / SpaceContent(open、highlight 中の項目)highlight 中の項目へ click を合成します。CheckboxItem は "toggle"、RadioItem は "select" を dispatch します(checked 状態機械は menu の MenuCheckboxItem/MenuRadioItemGroup を流用)。
印字可能文字Content(open)typeahead。ItemText 子があればそのテキストを優先してマッチします。
ArrowRightSubTrigger(highlight 中、水平配置)サブメニューを展開します。
ArrowLeftサブメニュー内(水平配置)親 SubTrigger へ復帰しサブメニューを閉じます。
Escape—開いている Menu を閉じます。フォーカスは元々 Trigger から離れないため、フォーカス復帰は構造的に成立します。
Tab / Shift+Tab—配線はありません(ブラウザ既定)。roving tabindex により tabindex="0" の Trigger のみが Tab 順序に含まれます。

参考サイトとの差分

参照基準は Radix Primitives Menubar のみです(ark-ui / chakra-ui / Radix Themes には Menubar 相当が存在しません)。Arrow/ArrowTip/ItemText/ ItemIndicator/CheckboxItem/RadioItemGroup/RadioItem の 7 パーツを新設し(11 → 18 anatomy パーツ)、各パーツ関数の呼び出し側 attrs から固定属性キーの偽装を除去する drop_reserved を全パーツへ適用しました。一方、以下は意図的に合わせていません。

  • Radix Portal: DOM 配置の関心のため不採用です(positioner が配置コンテナとして表現)。
  • content/sub-content の data-side/data-align: positioner へ attrs 経由で渡す既存設計のため置き換えていません。
  • sub-content の data-orientation: 不採用です。
  • RTL dir: 未対応です。
  • Root の value/defaultValue: 制御値は Menubar 状態機械の open: Option<usize> が担います。
  • Trigger の Space/Enter による実 DOM フォーカス移動: Trigger にフォーカスを留め data-highlighted(+ 実行時の aria-activedescendant)で仮想フォーカスを表現する設計のため未採用です。

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

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

自前 CSS の最小例

Themes 版を使わず本部品を直接使う場合、[data-scope="menubar"][data-part="..."] セレクタでスタイルを当てます。positioner/content/sub-content/item-indicator には [hidden] ガードを必ず含めます。

CSS
[data-scope="menubar"][data-part="positioner"][hidden],
[data-scope="menubar"][data-part="content"][hidden],
[data-scope="menubar"][data-part="sub-content"][hidden],
[data-scope="menubar"][data-part="item-indicator"][hidden] {
  display: none;
}

[data-scope="menubar"][data-part="trigger"][data-state="open"] {
  background: #eff6ff;
}

[data-scope="menubar"][data-part="item"][data-highlighted] {
  background: #eff6ff;
}

[data-scope="menubar"][data-part="item"][data-disabled] {
  color: #9ca3af;
}

[data-scope="menubar"][data-part="checkbox-item"][data-state="checked"] {
  font-weight: 600;
}

Demo

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

Features

  • 複数 Menu を水平(または垂直)に並べるコンテナ。Root / Menu / Trigger / Positioner / Content / Arrow / ArrowTip / Item / ItemText / ItemIndicator / ItemGroup / ItemGroupLabel / Separator / SubTrigger / SubContent / CheckboxItem / RadioItemGroup / RadioItem の 18 anatomy パーツを持つ(menubar.rs モジュール doc。Arrow/ArrowTip/ItemText/ItemIndicator/CheckboxItem/RadioItemGroup/RadioItem はイシュー #1652 で Radix Primitives Menubar と突合し追加、11 → 18 パーツ)。
  • roving tabindex(focused/trigger_count/open/loop_focus/orientation の複合状態機械 Menubar)。フォーカス対象のトリガーのみ tabindex="0"、それ以外は tabindex="-1" になる。
  • 開いている Menu を跨いだ左右移動: ある Menu が開いた状態で Next/Prev/First/Last/Focus を dispatch すると、フォーカス移動と同時に開く Menu も隣へ移る(menubar 特有の挙動、toolbar の roving tabindex にはない)。
  • menu パーツは role="none" を固定付与し、role="menubar" の子として menuitem/group 以外の要素を挟まないようにする(WAI-ARIA APG の menubar パターン)。
  • 既存の menu モジュールの anatomy はそのまま再利用せず data-scope="menubar" を独自に持つ。状態機械の値語彙(OpenState/aria/data-* ヘルパ)と checkbox_item/radio_item の checked 値語彙(checked_data_state)のみを再利用する。
  • 全パーツで呼び出し側 attrs による固定属性(role/aria-*/data-*/tabindex)の偽装を drop_reserved で除去する(イシュー #1652、A05)。

Anatomy

root
  menu
    trigger
    positioner
      content
        arrow
          arrow-tip
        item-group
          item-group-label
          item
        separator
        checkbox-item
          item-indicator
          item-text
        radio-item-group
          radio-item
        sub-trigger
          sub-content

API Reference

Arguments

NameTypeDefaultDescription
root(orientation)OrientationOrientation::Horizontalrole="menubar" に付与する向き。aria-orientation/data-orientation の両方へ反映される。
root(label)&str—root に付与する aria-label(空文字列のときは省略)。
trigger(focused)bool—true のとき tabindex="0"、false のとき tabindex="-1"(roving tabindex)。
trigger(state)OpenState—この Menu 自身の開閉状態。aria-expanded/data-state へ反映される。
checkbox_item(checked) / radio_item(checked)bool—checked/unchecked を role="menuitemcheckbox"/"menuitemradio" の aria-checked と data-state(checked_data_state 経由)へ反映する。
item_indicator(checked)bool—data-state(checked_data_state)へ反映し、unchecked のとき hidden 存在属性を付与する。aria-hidden="true" を固定付与。
item_text(disabled, highlighted)bool, bool—親 item 系パーツの状態を data-disabled/data-highlighted として装飾用に複製する。
sub_trigger(sub_state)OpenState—このトリガーが開閉するサブメニュー側の開閉状態(親 Menubar の state ではない)。aria-expanded/data-state へ反映する。

Data Attributes

PartAttributeObserved Values
checkbox-itemdata-statechecked, unchecked
checkbox-itemdata-valueminimap, word-wrap
contentdata-stateclosed, open
itemdata-disabled(値なし)
itemdata-highlighted(値なし)
itemdata-valueclose, new, pdf, png, undo
item-indicatordata-statechecked, unchecked
menudata-stateclosed, open
positionerdata-stateclosed, open
radio-itemdata-statechecked, unchecked
radio-itemdata-valuegrid, list
rootdata-orientationhorizontal
sub-contentdata-stateopen
sub-triggerdata-stateopen
triggerdata-disabled(値なし)
triggerdata-stateclosed, open
triggerdata-value0, 1, 2

Examples

2 個の Menu を並べた構成

File(open)/ Edit(closed)の 2 つの Menu を並べ、複数 Menu をまたぐ roving tabindex の構造を示します。

checkbox-item / radio-item-group を含む構成

checkbox-item(Word Wrap)と radio-item-group(Grid/List)を含む View メニューの構成例です。

自前 CSS を当てる最小例

data-scope="menubar" セレクタで hover/highlighted/disabled/checked のスタイルを当てる最小 CSS 例です。

CSS
[data-scope="menubar"][data-part="positioner"][hidden],
[data-scope="menubar"][data-part="content"][hidden],
[data-scope="menubar"][data-part="sub-content"][hidden],
[data-scope="menubar"][data-part="item-indicator"][hidden] {
  display: none;
}
[data-scope="menubar"][data-part="trigger"][data-state="open"] {
  background: #eff6ff;
}
[data-scope="menubar"][data-part="item"][data-highlighted] {
  background: #eff6ff;
}
[data-scope="menubar"][data-part="item"][data-disabled] {
  color: #9ca3af;
}
[data-scope="menubar"][data-part="checkbox-item"][data-state="checked"] {
  font-weight: 600;
}

Accessibility

Keyboard Interactions

KeyDescription
ArrowRight / ArrowLeft(trigger)隣の trigger へフォーカスを移動する(open-follows-focus: ある Menu が開いていれば開く Menu も追随する)。垂直 menubar では ArrowDown/ArrowUp が同じ役割を担う(menubar.rs「開いている Menu を跨いだ左右移動」節)。
ArrowDown / Space / Enter(trigger、closed)Menu を開き、先頭の非 disabled 項目を data-highlighted で仮想フォーカスする(実 DOM フォーカスは trigger に留まる)。
ArrowUp(trigger、closed)Menu を開き、末尾の非 disabled 項目を仮想フォーカスする。
ArrowDown / ArrowUp(content 内)項目間で data-highlighted を移動する(disabled はスキップする、fandhe-frontend-wasm-full の keynav::highlight_next_index が step_non_disabled へ委譲する)。
ArrowRight / ArrowLeft(sub-trigger)ArrowRight でサブメニューを展開、ArrowLeft で親トリガーへ復帰する(水平配置時。垂直配置は軸が入れ替わる)。
Home / Endcontent 内の先頭 / 末尾の非 disabled 項目へ仮想フォーカスを移動する(WAI-ARIA APG 準拠、Radix Menubar にはない拡張)。
印字可能文字(typeahead)item-text の子テキストをラベルとして前方一致検索し、一致する項目へ仮想フォーカスを移動する(WAI-ARIA APG 準拠)。
Escape開いている Menu を閉じる。trigger からフォーカスを離さない設計のため、フォーカス復帰は構造的に成立する。
Tab / Shift+Tab無配線(ブラウザ既定に委ねる)。roving tabindex により tabindex="0" のトリガーのみが Tab 順序に含まれる。

WAI-ARIA

AttributeDescription
role="menubar" / aria-orientationroot に固定付与。orientation 引数の値を反映する。
role="none"menu に固定付与(menubar の子として menuitem/group 以外を挟まないための WAI-ARIA APG 慣行)。
role="menuitem" / aria-haspopup="menu" / aria-expandedtrigger/sub-trigger に付与。開閉状態(この Menu の state、もしくはサブメニューの sub_state)を反映する。
role="menu"content/sub-content に固定付与。aria-labelledby は labelledby が Some のときのみ出力される。
role="menuitemcheckbox" / role="menuitemradio" / aria-checkedcheckbox-item/radio-item に付与。checked/unchecked の 2 値のみ(indeterminate は扱わない)。
aria-hidden="true"item-indicator に固定付与(装飾アイコンであり、親 checkbox-item/radio-item 自身の aria-checked が checked 状態を既に伝達するため)。