fix(ui5-li): implement edit mode for keyboard navigation in list items#13411
Open
fix(ui5-li): implement edit mode for keyboard navigation in list items#13411
Conversation
Collaborator
|
🚀 Deployed on https://pr-13411--ui5-webcomponents-preview.netlify.app |
Implements an edit mode for list items following the SAP Fiori Keyboard Interaction spec (Intentional Edit Pattern, p86-87): - **Navigation mode** (default): Tab/Shift+Tab forwards out of the list. Arrow keys navigate between items. - **Edit mode** (toggled by F2 or F7): Tab flows through inner focusable elements within an item, then continues to the next item's elements, and exits the list after the last item. Shift+Tab flows backward symmetrically. Arrow Up/Down transfers focus to the same-index element in adjacent items. The delete button in Delete selection mode is now keyboard accessible — reachable via edit mode Tab flow without requiring the Delete key shortcut. Fixes #13220
161576d to
a115c31
Compare
- Change _editMode from @Property to plain field to prevent re-render races in descendants like MenuItem during popover close sequences - Add e.stopPropagation() in List._handleF7 to prevent competing F7 handlers (e.g. Tokenizer's _onPopoverListKeydown) from undoing the focus set by the List's handler - Fix onForwardBefore ordering: set _editMode before getting focusable elements so the delete button is included - Restructure _handleF2 to set _editMode before checking focusables and use _getFocusableElements()[0] instead of getFirstFocusableElement - Add shadow-aware _indexOfActiveElement for correct focus tracking when the active element is inside a web component's shadow DOM
…-edit modes - Bridge _editing to _editMode so rename mode uses edit-mode Tab flow - Override _handleTabNext/_handleTabPrevious to use base class guards in non-edit mode, preserving pre-PR Tab cycling through action buttons
10 new tests covering: - F2/F7 no-op on items with no focusable elements - F2 no-op in Single/Multiple selection modes (radio/checkbox tabindex=-1) - Tab exit to growing button in edit mode - Shift+Tab from first item's first inner element exits list - F7 position memory clamping across items with different element counts - Edit mode cleared after focusout, navigation mode restored on re-entry - Arrow Down from item level uses standard navigation (not edit transfer) - Tab chain across items clears source item's edit mode via focusout
- Replace "\_editMode" in listItem type guard with the existing hasConfigurableMode pattern for consistency with the rest of List.ts - Clarify JSDoc: F2 is handled by ListItem, F7 by the parent List
a115c31 to
a933680
Compare
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
Implements an edit mode for list items following the SAP Fiori Keyboard Interaction spec (Intentional Edit Pattern, p86-87):
Tab/Shift+Tabforwards out of the list.Arrow Up/Downnavigates between items.F2orF7):Tabflows through inner focusable elements within an item, then continues to the next item's elements, and exits the list after the last item.Shift+Tabflows backward symmetrically.Arrow Up/Downtransfers focus to the same-index element in adjacent items.The delete button in
selectionMode="Delete"is now keyboard accessible — reachable via edit mode Tab flow without requiring theDeletekey shortcut.Changes
ListItem.ts_editModefield to track edit/navigation mode state (plain field, not@property— see rationale below)_handleTabNext/_handleTabPrevious— in edit mode, Tab cycles through inner elements; in navigation mode, firesforward-after/forward-beforeto exit the list_handleF2toggles edit mode on/off (synchronous, using_getFocusableElements)_onfocusouthandler to clear edit mode when focus leaves the component_indexOfActiveElement— shadow-aware focus matching so Tab correctly tracks the current position when an inner element (e.g.ui5-button) delegates focus to its shadow DOM childList.tsonForwardAfter/onForwardBefore: when the source item is in edit mode, routes focus to the adjacent item's inner elements instead of exiting the list_handleF7: sets_editModewhen entering/exiting internal elements; addede.stopPropagation()to prevent competing F7 handlers (e.g. Tokenizer's own F7 logic) from interfering_navigateToAdjacentItem: transfers_editModestate when arrow-navigating between itemsListItemBase.tsforward-beforeevent cancelable (consistent withforward-after)ListItemTemplate.tsxtabindex={-1}from the delete button, making it discoverable bygetTabbableElementsand focusable in edit modeUploadCollectionItem.ts(fiori package)_editing→_editMode: when the user enters rename mode via the edit button,_editModeis now also set so thatListItem._handleTabNextuses the edit-mode path and Tab can reach the rename/cancel buttons_handleTabNext/_handleTabPrevious: in non-edit mode, usesshouldForwardTabAfter()/shouldForwardTabBefore()guards fromListItemBaseso Tab cycles through always-visible action buttons (retry, edit, delete) without requiring F2. This is necessary becauseUploadCollectionItemfollows the Implicit Edit Pattern (spec p105-106) — its buttons should always be tabbable — whileListItemfollows the Intentional Edit Pattern where F2 is requiredList.cy.tsxListItemCustom+ custom delete button slotListEditMode.htmlDesign decisions
_editModeis a plain field, not@property: It controls keyboard navigation state, not rendering. As a reactive@propertyit triggered re-render cycles inListItemdescendants likeMenuItem(used insideMenu→NavigationMenu→SideNavigation), racing with popover focus restoration during menu close.e.stopPropagation()in_handleF7: The Tokenizer registers its own F7 handler (_onPopoverListKeydown) that directly queries[part=delete-button]and focuses it. WithoutstopPropagation, both handlers fire —List._handleF7focuses the button correctly, then the Tokenizer's handler overwrites it. Stopping propagation lets the List handle F7 exclusively when it has focusable elements.UploadCollectionItemTab overrides:ListItem._handleTabNextfiresforward-afterunconditionally in navigation mode (per the Intentional Edit Pattern). ButUploadCollectionItemhas always-visible action buttons that users expect to Tab through without F2. The override restoresListItemBase's original guard behavior for non-edit mode while delegating toListItem's edit-mode logic during rename operations.Test plan
ListEditMode.htmltest pageFixes #13220