Tree View
階層構造の展開・折りたたみ・選択を扱う部品です。fandhe-frontend-headless-ui の tree_view mod は 12 anatomy パーツと、展開集合 + 選択値を合成した状態機械を提供し、WAI-ARIA APG の Tree パターンに従う role="tree"/role="treeitem"/role="group" と aria-expanded/aria-selected/aria-level 等を出力します。Themes 版と異なりインデントガイドの見た目を持たず、構造とアクセシビリティ属性のみを担います。
キーボード操作
矢印キー・Home/End・Enter/Space・typeahead の DOM 配線は fandhe-frontend-wasm-full の keynav.rs(イシュー #1072)が担います(headless-ui 自体は SSR 静的マークアップのみ提供します)。
| キー | 効果 |
|---|---|
| ArrowDown / ArrowUp | 可視かつ disabled でない treeitem 間で 1 件ずつフォーカス移動します(折りたたみ中の子孫はスキップ、非循環)。 |
| ArrowRight | 閉じたブランチは展開します。開いたブランチは最初の子へフォーカス移動します。葉ノードでは no-op です。 |
| ArrowLeft | 開いたブランチは折りたたみます。それ以外(葉ノード・閉じたブランチ)は親ブランチへフォーカス移動します(ルート直下では no-op)。 |
| Home / End | 可視かつ disabled でない最初/最後の treeitem へフォーカス移動します。 |
| Enter / Space | 葉ノードは選択(select)、ブランチは開閉(toggle)を発火します。ブランチ自体は選択できません。 |
| 印字可能文字 | typeahead: 直近の入力から一致する treeitem へフォーカス移動します。 |
| Escape | typeahead バッファをリセットします。 |
参考サイトとの差分(イシュー #1667)
ark-ui docs の Data Attributes / Keyboard 表と zag.js packages/machines/tree-view/src/tree-view.connect.ts と突合し、以下を是正しました。Radix Primitives に Tree View 相当は存在しないため突合対象に含めていません。
branchへdata-branch(= ノード値)を追加しました。既存のdata-valueと同値ですが、[data-part="branch"][data-branch]セレクタでブランチ限定スタイルを書ける ark docs 準拠の別名です。branch-controlへdata-value/data-depthを追加しました。branch-indicatorへdata-disabled/data-selected/aria-hidden="true"を追加しました(装飾アイコンを支援技術から隠す ARIA APG の一般的な慣例)。branch-textへdata-state/data-disabledを追加しました。branch-contentへdata-depth/data-valueを追加しました。branch-indent-guideへdata-depthを追加しました。item-textへdata-selected/data-disabledを追加しました。item-indicatorへdata-disabled/aria-hidden="true"/非選択時hiddenを追加しました(選択されていない葉では選択マークを DOM 上非表示にします)。- 呼び出し側
attrsからの固定属性キー偽装を除去するdrop_reservedを全パーツへ追加しました。
一方、以下は意図的に合わせていません。
data-focus/data-renaming/data-checked/data-indeterminate/data-loading/aria-busy: focus・rename・checkbox・lazy loading という実行時ローカル状態であり、SSR に実データがないため非採用です。data-path/data-ownedby/id/dir/tabindex/--depthstyle:fandhe-frontend-wasm-fullはdata-valueの文字列比較と document 順走査で親子解決するため不要です。tabindexは wasm-full の roving tabindex が実行時に付与します。aria-multiselectable: 本部品は単一選択(SingleSelect)のみを提供するため対象外です。aria-current="true"(zag の item): WAI-ARIA APG Tree ではaria-selectedが選択の正であり重複させません。role="button"on branch-control: APG ではフォーカス可能要素は treeitem(branch)が担うため、入れ子の widget ロールを避けています。- branch-trigger / node-checkbox / node-rename-input: ark Anatomy 図に載らないパーツです。checkbox モード・inline rename は本部品のスコープ外です。
*(兄弟一括展開)・Shift+Arrow / Ctrl+A(複数選択前提)・F2(rename): いずれも zag.js のみが持つ拡張操作、または複数選択・rename 前提の操作のため非採用です。
APG superset として維持しているもの:
aria-posinset/aria-setsize(zag は出力しません)。- disabled 時も明示する
aria-selected="false"(zag は disabled 時に省略します)。
data-depth の起点: zag.js は depth = indexPath.length(トップレベル = 1 起点)ですが、本部品は 0 起点を意図的に維持しています。aria-level が 1 起点の深さを既に担っており、fandhe-frontend-wasm-full の keynav.rs が depth == 0 をルート判定に使う実装との整合を優先しました。
スタイル済みの表示例は Tree View を参照してください。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
Themes 版を使わず本部品を直接使う場合、[data-scope="tree-view"][data-part="..."] セレクタでスタイルを当てます。branch-content/item-indicator は base 規則で display を宣言する構成にすると UA 既定の [hidden] { display: none } を上書きしてしまうため、[hidden] 属性セレクタで明示的に上書きが必要です。ただし上書き先は両者で異なります。branch-content は子ノード列そのものを畳むコンテナのため display: none で問題ありませんが、item-indicator は選択マーク幅の列を揃える整列用スペーサでもあるため display: none にすると非選択葉の item-text が選択済み葉・branch-text に対して列幅分だけ左へ寄る視覚崩れが生じます。visibility: hidden でレイアウトボックスを残したまま非表示にします(支援技術からの除外は headless 層が固定出力する aria-hidden="true" が既に担います)。
[data-scope="tree-view"][data-part="branch-content"][hidden] {
display: none;
}
[data-scope="tree-view"][data-part="item-indicator"][hidden] {
visibility: hidden;
}
[data-scope="tree-view"][data-part="branch-indent-guide"] {
width: 1rem;
}
[data-scope="tree-view"][data-part="branch-control"][data-selected],
[data-scope="tree-view"][data-part="item"][data-selected] {
background: #eff6ff;
}
[data-scope="tree-view"][data-part="branch-control"][data-disabled],
[data-scope="tree-view"][data-part="item"][data-disabled] {
opacity: 0.5;
}
[data-scope="tree-view"][data-part="branch-control"]:focus-visible,
[data-scope="tree-view"][data-part="item"]:focus-visible {
outline: 2px solid #2563eb;
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- Root / Label / Tree / Branch / BranchControl / BranchIndicator / BranchText / BranchContent / BranchIndentGuide / Item / ItemText / ItemIndicator の 12 anatomy パーツを提供する(tree_view.rs:1-10)。
- 展開集合(MultiSelect)+ 選択値(SingleSelect)を合成した状態機械 TreeView を提供し、TreeView::render_nodes が深さ・aria-posinset/aria-setsize を再帰的に計算する(tree_view.rs:636-758)。
- tree は role="tree"、branch/item は role="treeitem"、branch_content は role="group" を固定出力する WAI-ARIA APG Tree パターン準拠(tree_view.rs:291-487)。
- branch/item は disabled=true のとき aria-disabled="true" を対で付与する(ネイティブ disabled を持たない role="treeitem" のための代替、tree_view.rs:340-344,476-480)。
- ark-ui docs / zag.js との参照突合(イシュー #1667)で data-branch(branch)・data-value/data-depth(branch-control)・data-selected/data-disabled/data-state(インジケータ・テキスト系)・非選択時 hidden(item-indicator)を追加した(tree_view.rs 冒頭「参照突合(イシュー #1667)」節)。
- 矢印キー・Home/End・Enter/Space・typeahead の DOM 配線は fandhe-frontend-wasm-full keynav.rs §TreeView(イシュー #1072)が担う。* による兄弟一括展開・Shift+Arrow/Ctrl+A(複数選択前提)・F2(rename)は非追随(tree_view.rs 冒頭「out-of-scope」節)。
Anatomy
root
label
tree
branch
branch-control
branch-indicator
branch-text
branch-content
branch-indent-guide
item
item-indicator
item-textAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
tree: aria_label_text, aria_labelledby_id | Option<&str>, Option<&str> | None, None | tree のアクセシブルな名前(いずれか片方が Some を推奨、tree_view.rs:291-306)。 |
TreeItemProps: value, selected, disabled, level, posinset, setsize, depth | &str, bool, bool, &str, &str, &str, &str | — | branch/branch_control/branch_indicator/branch_text/branch_content/branch_indent_guide/item/item_text/item_indicator へ一括で通すノード共通プロパティ(level/posinset/setsize/depth は呼び出し側が usize から文字列化した aria-level/aria-posinset/aria-setsize/data-depth、イシュー #1667 で新設、tree_view.rs 内 TreeItemProps 定義)。 |
TreeView::render_nodes: nodes | &[TreeNode] | — | 決定的な静的木を現在の展開・選択状態で再帰描画する(tree_view.rs:681-683)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
branch | data-branch | docs, src |
branch | data-depth | 0 |
branch | data-state | closed, open |
branch | data-value | docs, src |
branch-content | data-depth | 0 |
branch-content | data-state | closed, open |
branch-content | data-value | docs, src |
branch-control | data-depth | 0 |
branch-control | data-state | closed, open |
branch-control | data-value | docs, src |
branch-indent-guide | data-depth | 0 |
branch-indicator | data-state | closed, open |
branch-text | data-state | closed, open |
item | data-depth | 0, 1 |
item | data-disabled | (値なし) |
item | data-selected | (値なし) |
item | data-value | README.md, guide.md, lib.rs |
item-indicator | data-disabled | (値なし) |
item-indicator | data-selected | (値なし) |
item-text | data-disabled | (値なし) |
item-text | data-selected | (値なし) |
Examples
Closed branch
branch が折りたたまれ、branch_content が hidden の例です(Demo は展開済み)。
Custom CSS
headless 層は data-scope/data-part/data-* のみを出力し外観を持たないため、branch-content の hidden 上書き・branch-indent-guide の幅・選択状態の強調を自前 CSS で当てる最小例です。
headless-ui はスタイルを持たないため、data-scope="tree-view"/data-part 属性セレクタで自前 CSS を当てる最小例です。
[data-scope="tree-view"][data-part="branch-content"][hidden] {
display: none;
}
[data-scope="tree-view"][data-part="branch-indent-guide"] {
width: 1rem;
}
[data-scope="tree-view"][data-part="branch-control"][data-selected],
[data-scope="tree-view"][data-part="item"][data-selected] {
background: #eff6ff;
}
[data-scope="tree-view"][data-part="branch-control"][data-disabled],
[data-scope="tree-view"][data-part="item"][data-disabled] {
opacity: 0.5;
}
[data-scope="tree-view"][data-part="branch-control"]:focus-visible,
[data-scope="tree-view"][data-part="item"]:focus-visible {
outline: 2px solid #2563eb;
}
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| ArrowDown / ArrowUp | 可視かつ disabled でない treeitem 間で 1 件ずつフォーカス移動する(折りたたみ中の子孫はスキップ、非循環)。 |
| ArrowRight | 閉じたブランチは展開する。開いたブランチは最初の子へフォーカス移動する。葉ノードでは no-op。 |
| ArrowLeft | 開いたブランチは折りたたむ。それ以外(葉ノード・閉じたブランチ)は親ブランチへフォーカス移動する(ルート直下では no-op)。 |
| Home / End | 可視かつ disabled でない最初/最後の treeitem へフォーカス移動する。 |
| Enter / Space | 葉ノードは選択(select)、ブランチは開閉(toggle)を発火する(ブランチ自体は選択できない)。 |
| 印字可能文字 | typeahead: 直近の入力から一致する treeitem へフォーカス移動する。 |
| Escape | typeahead バッファをリセットする。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| role="tree" / role="treeitem" / role="group" | tree/branch・item/branch_content に固定出力する(tree_view.rs:291-487)。 |
| aria-expanded | branch のみ(open/closed を反映、tree_view.rs:322-325)。 |
| aria-selected / aria-level / aria-posinset / aria-setsize | branch/item 双方に出力する(disabled 時も aria-selected="false" を省略しない APG superset、tree_view.rs:322-329,459-466)。 |
| aria-disabled="true" | disabled=true のときのみ branch/item に出力する(tree_view.rs:340-344,476-480)。 |
| aria-hidden="true" | branch-indicator/item-indicator(装飾アイコン)に固定出力する(イシュー #1667 で追加、tree_view.rs 内 branch_indicator/item_indicator 定義)。 |