Skip to content

fix(core): restore tree keyboard navigation - #273

Merged
johnyanarella merged 1 commit into
mainfrom
topic/fix-tree-keyboard-navigation
Sep 3, 2026
Merged

fix(core): restore tree keyboard navigation#273
johnyanarella merged 1 commit into
mainfrom
topic/fix-tree-keyboard-navigation

Conversation

@johnyanarella

@johnyanarella johnyanarella commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Restores tree keyboard navigation after clicking a node label. The tree header is again the single roving-focus target; pointer activation resolves noninteractive label content to that header while preserving focus for nested controls. It also cancels browser scrolling on keydown for tree-owned Space and expandable Left/Right commands.

This restores composed-path resolution for pointer activation removed in b853178, while preserving exact-target keyboard handling so nested interactive controls retain their own focus.

Summary by CodeRabbit

  • Bug Fixes
    • Improved tree and list keyboard navigation and focus behavior.
    • Clicking non-interactive nested content now activates and focuses its containing item.
    • Interactive descendants retain focus without activating the containing item.
    • Prevented unwanted scrolling when using Space or expansion arrow keys.
    • Clicking a tree node label now correctly focuses the node and supports ArrowDown navigation.
    • Improved focus management when moving between tree nodes with keyboard controls.

#getActiveItem(e: Event, items: HTMLElement[]) {
const focusedElement = e.composedPath()[0] as HTMLElement;
return items.find(i => i === focusedElement) ? focusedElement : null;
#getKeyboardActiveItem(e: KeyboardEvent, items: HTMLElement[]) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keyboard navigation intentionally remains exact-target only. This prevents tree navigation from taking Arrow keys away from a focused nested control such as a link, button, or input.

return target instanceof HTMLElement && items.includes(target) ? target : null;
}

#getPointerActiveItem(e: PointerEvent, items: HTMLElement[]) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pointer interaction may begin on nonfocusable slotted label content, so resolve the registered header through the composed path. Stop at a focusable descendant to preserve that control’s native focus.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: e302ded0-966c-4bdc-8971-a5103a5f7b1b

📥 Commits

Reviewing files that changed from the base of the PR and between ce3c8ab and 560ce19.

📒 Files selected for processing (2)
  • projects/core/src/menu/menu.test.lighthouse.ts
  • projects/core/src/pagination/pagination.test.lighthouse.ts

Included review availability: Your plan provides up to 12 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Changes

The changes separate pointer and keyboard list-item resolution. They update tree-node focus behavior and prevent default browser actions for Space and expansion keys while preserving selection and expansion handling. Lighthouse thresholds reflect updated bundle sizes.

Tree navigation interaction

Layer / File(s) Summary
Separate pointer and keyboard target resolution
projects/core/src/internal/controllers/keynav-list.controller.ts, projects/core/src/internal/controllers/keynav-list.controller.test.ts
Pointer handling finds list items through the composed path and ignores focusable descendants. Keyboard handling accepts directly targeted list items. Tests cover non-focusable descendants and nested buttons.
Tree-node focus and keyboard handling
projects/core/src/tree/tree-node.ts, projects/core/src/tree/tree-node.test.ts
The title slot no longer creates a tab stop. Tree nodes cancel default behavior for Space and expansion keys during keydown, while selection and expansion remain on keyup. Tests cover focus retention and keyboard state changes.
Tree navigation integration coverage
projects/core/src/tree/tree.test.ts
Tests cover label-click focus, roving tabIndex, ArrowDown navigation, and the nve-key-change event detail.
Bundle-size threshold updates
projects/core/src/index.test.lighthouse.ts, projects/core/src/menu/menu.test.lighthouse.ts, projects/core/src/pagination/pagination.test.lighthouse.ts, projects/core/src/tree/tree.test.lighthouse.ts
Lighthouse tests update JavaScript payload thresholds for the affected bundles.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 560ce

This PR restores tree keyboard navigation and preserves focus for nested controls without introducing an actionable merge-blocking risk; it is merge-ready after normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: restoring tree keyboard navigation after clicking a node label.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 9…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 9 files.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch topic/fix-tree-keyboard-navigation

Warning

Some tools did not complete. Review the errors below.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

projects/core/src/menu/menu.test.lighthouse.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

projects/core/src/pagination/pagination.test.lighthouse.ts

ESLint skipped: the matched ESLint configuration already failed (missing-dependency).


Comment @coderabbitai help to get the list of available commands.

}
<div tabindex="0" part="_node-header">
<slot tabindex="0" class="node-title" @click=${this.#nodeHeaderClick}></slot>
<slot class="node-title" @click=${this.#nodeHeaderClick}></slot>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The node header is the canonical roving-focus target. Giving the label slot its own tab stop created a competing, unmanaged focus target and left keyboard navigation unable to identify the active tree item.

this.#isExpandable ? this._internals.states.add('is-expandable') : this._internals.states.delete('is-expandable');
}

#onKeydown = (e: KeyboardEvent) => {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tree selection and expansion actions occur on keyup, but browser scrolling is a keydown default. Cancel the default here while allowing the event to continue bubbling for application listeners.

@johnyanarella
johnyanarella force-pushed the topic/fix-tree-keyboard-navigation branch from 64fa9e7 to ce3c8ab Compare September 3, 2026 00:08
Signed-off-by: John Yanarella <jyanarella@nvidia.com>
@johnyanarella
johnyanarella force-pushed the topic/fix-tree-keyboard-navigation branch from ce3c8ab to 560ce19 Compare September 3, 2026 00:13
@johnyanarella
johnyanarella merged commit e024c11 into main Sep 3, 2026
15 checks passed
@johnyanarella
johnyanarella deleted the topic/fix-tree-keyboard-navigation branch September 3, 2026 01:44
@coryrylan

Copy link
Copy Markdown
Collaborator

🎉 This issue has been resolved in version 2.7.2 🎉

Changelog

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants