diff --git a/packages/ui/packages/registry/components/tabs.ts b/packages/ui/packages/registry/components/tabs.ts index 24da7c92b..c94995408 100644 --- a/packages/ui/packages/registry/components/tabs.ts +++ b/packages/ui/packages/registry/components/tabs.ts @@ -241,7 +241,13 @@ export class UiTabsTrigger extends WebComponent({ const tabs = this._tabs; if (!tabs) return; const orientation = tabs.orientation; - const triggers = Array.from(tabs.querySelectorAll('ui-tabs-trigger')); + // Scope to triggers belonging to THIS group: querySelectorAll crosses into + // a nested inside a panel, and arrow nav at the boundary would + // jump into the inner group and set this group's value to an inner-only + // value (hiding every panel). Same scoping dropdown-menu applies to items. + const triggers = Array.from(tabs.querySelectorAll('ui-tabs-trigger')).filter( + (t) => t._tabs === tabs, + ); const idx = triggers.indexOf(this); const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'; const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'; @@ -257,7 +263,13 @@ export class UiTabsTrigger extends WebComponent({ e.preventDefault(); const v = target.value; if (v) tabs.setAttribute('value', v); - target.focus(); + // Focus the inner + + Profile + Billing + Settings + + + `); + const menuEl = root.querySelector('ui-dropdown-menu'); + const items = [...root.querySelectorAll('ui-dropdown-menu-item [role="menuitem"]')]; + menuEl.show(); + await tick(); + assert.equal(document.activeElement, items[0], 'first item focused on open'); + items[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })); + await tick(); + assert.equal(document.activeElement, items[1], 'ArrowDown -> second item'); + items[1].dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true })); + await tick(); + assert.equal(document.activeElement, items[0], 'ArrowUp -> first item'); + items[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })); + await tick(); + assert.equal(menuEl.open, false, 'Escape closes the menu'); + root.remove(); + }); }); suite('ui-dialog a11y', () => {