feat(ui5-bar): add arrow left/arrow right/home/end navigation - #13977
feat(ui5-bar): add arrow left/arrow right/home/end navigation#13977NHristov-sap wants to merge 2 commits into
Conversation
👋 Heads-up: dev close is in effectThanks for the contribution! This repository is currently in dev close ahead of release This PR appears to introduce public-API changes (detected by diffing the Custom Elements Manifest against the latest published version on npm):
Could you please hold off on merging into If this change must ship in the current release, please request a review from one or two members of @UI5/ui5-team-webc so the team can sign off explicitly.
Posted automatically by the Dev Close Notice workflow. |
|
🚀 Deployed on https://pr-13977--ui5-webcomponents-preview.netlify.app |
| e.stopPropagation(); | ||
| } | ||
|
|
||
| _isNodeInsideElement(node: Node, element: HTMLElement): boolean { |
There was a problem hiding this comment.
this is absolutely identical with the same method in the Toolbar.ts, we could extract it in a until, e.g. in the base/packages
There was a problem hiding this comment.
Sure, we can think on it.
| const result: Array<HTMLElement> = []; | ||
|
|
||
| slotSelectors.forEach(sel => { | ||
| const slotEl = this.shadowRoot!.querySelector<HTMLSlotElement>(sel); |
There was a problem hiding this comment.
something minor, but let's use more descriptive names here:
sel → slottedElement / slotElement
el → elementInBar or something that makes sense
| if (isHomeKey || isEndKey) { | ||
| return; | ||
| } | ||
| if (isForward && input.selectionStart !== input.value.length) { |
There was a problem hiding this comment.
For inputs where selectionStart returns null, this check will result in !== 0 being true, and the navigation will be trapped.
| ResizeHandler.register(child as HTMLElement, this._handleResizeBound); | ||
| }, this); | ||
|
|
||
| this.addEventListener("keydown", this._onKeyDownBound, true); |
There was a problem hiding this comment.
This listener steals keys if we have slotted self-navigating child elems. For example slotted slider, segmented button, or breadcrumb loses their own Left/Right/Home/End at the bar boundary.
I think in the Toolbar they use this util, to go around it - getArrowNavState(), please double-check.
There was a problem hiding this comment.
Yep, good point. It steals kbd navigation and wouldn't work if there is such component there. The problem is that getArrowNavState should be implemented in all components that have its own arrow handling.
| return; | ||
| } | ||
|
|
||
| items[nextIndex].focus(); |
There was a problem hiding this comment.
Is it supposed to be changed? In my opinion - NO!
| return this.accessibleRole.toLowerCase() === "toolbar" ? "toolbar" as AriaRole : undefined; | ||
| } | ||
|
|
||
| _collectFocusableElements(): Array<HTMLElement> { |
There was a problem hiding this comment.
Can we use getTabbableElements here ?
There was a problem hiding this comment.
Nope, because getTabbableElements return ALL tabbable elements (for example each segmented button item, and using it to focus an element later would break default behaviour of the components that use item navigation or similar mechanism.

The WAI-ARIA toolbar pattern requires that interactive controls inside a toolbar are navigable with arrow keys. Without this, keyboard users have no standard way to move between actions in the bar other than Tab, which is cumbersome when many controls are present.
This PR introduces arrow key navigation to
ui5-bar. When the bar hasrole="toolbar"(the default), pressingArrowRight/ArrowLeftmoves focus between all focusable elements across the bar's three slots (startContent,middle/default,endContent) in DOM order.HomeandEndjump directly to the first or last focusable item. Text inputs inside the bar are handled carefully — arrow keys only leave the input when the cursor is already at its edge, so normal text editing still works as expected.ui5-barcomponents withaccessibleRoledifferent thanToolbarare unaffected.