From b1fdca563b4cc470a1ec2b4898aee751f28d1716 Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Wed, 29 Oct 2025 11:27:34 -0400 Subject: [PATCH 1/2] fix(aria/menu): lazy render trigger --- src/aria/menu/menu.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 308c5045ab56..83cdcdaa5a0f 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -51,6 +51,7 @@ import {DeferredContent, DeferredContentAware} from '@angular/aria/deferred-cont '(click)': '_pattern.onClick()', '(keydown)': '_pattern.onKeydown($event)', '(focusout)': '_pattern.onFocusOut($event)', + '(focusin)': 'onFocusIn()', }, }) export class MenuTrigger { @@ -65,6 +66,9 @@ export class MenuTrigger { /** The menu associated with the trigger. */ menu = input | undefined>(undefined); + /** Whether the menu item has been focused. */ + readonly hasBeenFocused = signal(false); + /** The menu trigger ui pattern instance. */ _pattern: MenuTriggerPattern = new MenuTriggerPattern({ element: computed(() => this._elementRef.nativeElement), @@ -74,6 +78,11 @@ export class MenuTrigger { constructor() { effect(() => this.menu()?.parent.set(this)); } + + /** Marks the menu trigger as having been focused. */ + onFocusIn() { + this.hasBeenFocused.set(true); + } } /** @@ -185,7 +194,9 @@ export class Menu { }); afterRenderEffect(() => { - this._deferredContentAware?.contentVisible.set(this._pattern.isVisible()); + this._deferredContentAware?.contentVisible.set( + this._pattern.isVisible() || !!this.parent()?.hasBeenFocused(), + ); }); // TODO(wagnermaciel): This is a redundancy needed for if the user uses display: none to hide @@ -322,6 +333,7 @@ export class MenuBar { host: { 'role': 'menuitem', 'class': 'ng-menu-item', + '(focusin)': 'onFocusIn()', '[attr.tabindex]': '_pattern.tabindex()', '[attr.data-active]': '_pattern.isActive()', '[attr.aria-haspopup]': '_pattern.hasPopup()', @@ -363,6 +375,9 @@ export class MenuItem { /** The submenu associated with the menu item. */ readonly submenu = input | undefined>(undefined); + /** Whether the menu item has been focused. */ + readonly hasBeenFocused = signal(false); + /** The menu item ui pattern instance. */ readonly _pattern: MenuItemPattern = new MenuItemPattern({ id: this.id, @@ -377,6 +392,11 @@ export class MenuItem { constructor() { effect(() => this.submenu()?.parent.set(this)); } + + /** Marks the menu item as having been focused. */ + onFocusIn() { + this.hasBeenFocused.set(true); + } } /** Defers the rendering of the menu content. */ From 844a7ce30dd47e940c99d5eae51025aace47716a Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Wed, 29 Oct 2025 12:14:33 -0400 Subject: [PATCH 2/2] fixup! fix(aria/menu): lazy render trigger --- src/aria/menu/menu.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 83cdcdaa5a0f..ce6959094e52 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -194,9 +194,14 @@ export class Menu { }); afterRenderEffect(() => { - this._deferredContentAware?.contentVisible.set( - this._pattern.isVisible() || !!this.parent()?.hasBeenFocused(), - ); + const parent = this.parent(); + if (parent instanceof MenuItem && parent.parent instanceof MenuBar) { + this._deferredContentAware?.contentVisible.set(true); + } else { + this._deferredContentAware?.contentVisible.set( + this._pattern.isVisible() || !!this.parent()?.hasBeenFocused(), + ); + } }); // TODO(wagnermaciel): This is a redundancy needed for if the user uses display: none to hide