Skip to content

feat(ui): add accessible tree suite - #1065

Draft
EhabY wants to merge 3 commits into
feat/ui-package-gapsfrom
feat/ui-tree-suite
Draft

feat(ui): add accessible tree suite#1065
EhabY wants to merge 3 commits into
feat/ui-package-gapsfrom
feat/ui-tree-suite

Conversation

@EhabY

@EhabY EhabY commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add the Tree, TreeItem, TreeGroup, and TreeIndentGuide component suite
  • add controlled selection and expansion with ARIA tree semantics, roving tabindex, hierarchy navigation, and buffered type-ahead
  • match VS Code 1.131 tree geometry and states, with separate shared, Modern, and stable styles
  • add Storybook coverage across Light, Dark, High Contrast, and High Contrast Light
  • use an observable useSyncExternalStore registry with batched reconciliation and per-item snapshots
  • add focused component and keyboard-navigation tests

Stack

Closes #1037

Validation

  • pnpm test:webview — 357 tests passed
  • pnpm typecheck
  • NODE_OPTIONS=--max-old-space-size=4096 pnpm lint
  • pnpm format:check
  • pnpm storybook:ci
  • pnpm build
  • git diff --check

Pixel snapshots were not submitted locally because PIXEL_KEY was unavailable.

Implementation plan and decisions

API and state

  • Compound hierarchy: Tree > TreeItem > TreeGroup > TreeItem
  • Required stable itemId and textValue
  • Controlled single selection through Tree.selectedItemId and Tree.onSelectedItemChange
  • Controlled branch expansion through TreeItem.expanded and TreeItem.onExpandedChange
  • No uncontrolled state or multi-selection API

Behavior

  • Observable registry-based roving tabindex navigation with batched ordering and per-item snapshots
  • Arrow Up/Down, Home/End, Left/Right, Enter/Space, and buffered type-ahead
  • Enter and Space select the focused row and toggle branches
  • Disabled and collapsed descendants are excluded; disabled rows cannot be programmatically activated
  • Trailing interactive actions are isolated from tree selection and expansion
  • Optional logical indexes and focus callbacks provide integration hooks for externally managed rows

Styling

  • Tree.css contains shared structure and states
  • Tree.modern.css contains the Modern UI row inset, radius, and keyboard-only focus behavior
  • Tree.stable.css contains stable focus behavior; edge-to-edge square geometry follows from excluding Modern rules
  • Modern UI is the package default; data-ui-style="stable" selects stable styling
  • Semantic list and tree tokens map to VS Code theme variables
  • Native 22px rows, 30px twistie allocation, 8px level offsets, and 16/24/32px indent guides

Coverage

  • ARIA hierarchy, selection, expansion, disabled state, and accessible names
  • Keyboard navigation, activation, type-ahead, controlled and metadata updates, and event isolation
  • Stories across all four supported VS Code theme families, with stable variations only where they render differently from Modern

This PR was generated with Coder Agents.

Native tree visual audit

  • extracted the VS Code 1.131 tree ground truth from the installed bundle (abstractTree.ts indent math, injected list styles, .style-override Modern rules) and verified against a live code serve-web explorer DOM: Modern rows are inset 4px with a 4px radius, guides sit at 16px + 8px per level, active guide owners derive from focus and selection, and inactive guides show only on hover
  • the twistie gutter now follows the two native modes: the default keeps the 22px gutter on every row (for trees whose branch rows render icons), while variant="explorer" collapses the unused leaf gutter so file icons align with branch twisties, matching the native default Explorer whose folders render without icons — mixing folder icons with the collapsed gutter was what ran the active indent guide through leaf file icons
  • the Tree story mirrors the native default Explorer (chevron-only folders, file icons on leaves), and guide visibility matches native: the active guide is always visible while inactive guides fade in only while the tree is hovered (verified against computed styles with a real pointer)
  • simplified the store: per-item snapshots are read straight through the store subscription instead of a per-item observer registry, one registration path replaces registerElement plus the ready flag, the ancestor-path cache is gone, and the interactive-target selector is shared with TreeItem
  • consolidated stories to stable variations only where Modern and stable differ (Tree, TreeItem), added collapsed-branch coverage, and made the Tree play reveal the row action through selection so it no longer depends on the window holding OS focus

@EhabY EhabY self-assigned this Aug 5, 2026
@EhabY
EhabY force-pushed the feat/ui-tree-suite branch from 510e466 to 309f05d Compare August 5, 2026 14:11
EhabY added 2 commits August 5, 2026 18:16
…uite

Drop the explorer variant: collapsing leaf twisties belongs to icon
themes without folder icons, and combined with folder icons it ran the
active indent guide through leaf file icons. Every row now keeps the
native gutter, matching the VS Code 1.131 default explorer.

Simplify the tree store: items subscribe to the store directly through
per-item snapshots instead of a per-item observer registry, a single
registration path replaces registerElement plus the ready flag, and the
ancestor-path cache goes away. Share the interactive-target selector
with TreeItem.

Trim the stories to variations that differ: stable snapshots stay only
where row geometry or focus behavior diverges from Modern, TreeItem
gains collapsed-branch coverage, and the Tree play reveals the row
action through selection so it no longer depends on window focus.
The native default Explorer renders folders without icons and aligns
leaf file icons with the branch twisties, so bring back
variant="explorer" for that mode and document when it applies: branch
rows with icons keep the default gutter, or leaf icons would sit on the
indent guides. The Tree story now mirrors the native default Explorer
with chevron-only folders.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ui: Tree suite with native-fidelity look and ARIA keyboard nav

1 participant