feat: implement roving tabindex for TreeView and GridView#513
Merged
Conversation
295583d to
a2f0468
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Implements roving tabindex behavior for TreeView and GridView so each widget becomes a single Tab stop with internal arrow-key navigation, and adds an example page for manual verification.
Changes:
- Add active-item tracking and focus-in logic to support roving tabindex and “Tab-in selects active item” behavior in TreeView and GridView.
- Update selected styling to also apply on
:focus-visiblefor clearer keyboard focus indication. - Add a new
tabindex.htmlexample and link it from the example browser.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/components/TreeView/style.scss | Apply selected styling on :focus-visible for focused TreeView rows. |
| src/components/TreeView/index.ts | Add _activeItem roving-tabindex state, focus-in handling, and adjust key handling (stop intercepting Tab). |
| src/components/GridViewItem/style.scss | Apply selected styling on :focus-visible for GridView items. |
| src/components/GridView/index.ts | Add _activeItem roving-tabindex state and focus-in handling; update active item on selection/removal. |
| examples/index.html | Add “TabIndex” entry to examples list. |
| examples/elements/tabindex.html | New demo page for manual testing of roving tabindex behavior. |
Comments suppressed due to low confidence (1)
src/components/GridView/index.ts:162
_onAppendGridViewItemsets the active (tabbable) item before applyingfilterFn. If the first appended item gets hidden by the filter, it can remain the active item withtabIndex=0, leaving the GridView with no visible tabbable item under the new roving-tabindex behavior. Consider applying filtering first and/or re-homing_activeItemto the next visible item whenever the active item becomes hidden.
if (!this._activeItem) {
this._setActiveItem(item);
} else {
item.dom.tabIndex = -1;
}
let evtClick: EventHandle;
if (this._clickFn) {
evtClick = item.on('click', evt => this._clickFn(evt, item));
} else {
evtClick = item.on('click', evt => this._onClickItem(evt, item));
}
let evtSelect = item.on('select', () => this._onSelectItem(item));
let evtDeselect: EventHandle;
if (this._allowDeselect) {
evtDeselect = item.on('deselect', () => this._onDeselectItem(item));
}
if (this._filterFn && !this._filterFn(item)) {
item.hidden = true;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
a2f0468 to
840c190
Compare
Each widget now acts as a single Tab stop with internal arrow key navigation (WAI-ARIA roving tabindex pattern). On keyboard Tab-in, the focused item is auto-selected using :focus-visible detection. A :focus-visible CSS rule mirrors the selected style so the active item is always visually apparent. Adds a tabindex.html example for manual testing. Made-with: Cursor
840c190 to
9a9419b
Compare
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Covers single tabIndex=0 invariant, active item tracking selection, active item reassignment on removal, and focus-in-from-outside auto-selection. Also fixes GridView _onRemoveGridViewItem to find the next active item from remaining DOM children rather than the detached item's siblings. Made-with: Cursor
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Matches the TreeView fix: only select the focused item if it is not already selected, avoiding collapse of an existing multi-selection when tabbing back into the widget. Made-with: Cursor
During filtering, non-filter-result items are now skipped. Outside filtering, explicitly hidden items are skipped. Uses item.hidden instead of offsetParent for jsdom compatibility. Made-with: Cursor
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
willeastcott
added a commit
that referenced
this pull request
Mar 4, 2026
…and GridView The roving tabindex PR (#513) added a :focus-visible CSS rule that shared the same background as selected items. When focus remained on a deselected item (e.g. after clicking a non-focusable element), the item appeared selected. Also simplifies _onFocusIn to only track the active item for roving tabindex without auto-selecting. Made-with: Cursor
3 tasks
willeastcott
added a commit
that referenced
this pull request
Mar 4, 2026
…and GridView The roving tabindex PR (#513) added a :focus-visible CSS rule that shared the same background as selected items. When focus remained on a deselected item (e.g. after clicking a non-focusable element), the item appeared selected. Also simplifies _onFocusIn to only track the active item for roving tabindex without auto-selecting. Made-with: Cursor
willeastcott
added a commit
that referenced
this pull request
Mar 4, 2026
…and GridView (#518) The roving tabindex PR (#513) added a :focus-visible CSS rule that shared the same background as selected items. When focus remained on a deselected item (e.g. after clicking a non-focusable element), the item appeared selected. Also simplifies _onFocusIn to only track the active item for roving tabindex without auto-selecting. Made-with: Cursor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
:focus-visible) and the active item tracks selection so Tab-back always returns to the last selected item:focus-visibleCSS rules that mirror the selected style, providing a visual focus indicator for keyboard usersTabfrom the set of keys thatTreeViewintercepts, allowing native Tab behavior to move focus out of the widgettabindex.htmlexample page for manual testingTest plan
tabindex.htmlexample and verify Tab moves into the TreeView (first item highlights and is selected), arrow keys navigate within it, and Tab moves out to the GridViewnpm testand confirm all tests pass