From cf6321f84d29e68bd27dfd93c63fdabb638102e9 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Wed, 4 Mar 2026 12:59:33 +0100 Subject: [PATCH] fix(aria/menu): itemSelected not emitted when menu is attached to a trigger The logic that dispatches `itemSelected` wasn't accounting for the case where the menu root is a trigger. Fixes #32865. --- src/aria/menu/menu.spec.ts | 17 +++++++++++++++-- src/aria/private/menu/menu.ts | 31 +++++++++++++------------------ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/aria/menu/menu.spec.ts b/src/aria/menu/menu.spec.ts index e97a79243ce5..ed6ab2f662d7 100644 --- a/src/aria/menu/menu.spec.ts +++ b/src/aria/menu/menu.spec.ts @@ -626,6 +626,17 @@ describe('Menu Trigger Pattern', () => { expect(isExpanded()).toBe(false); }); }); + + describe('Selection', () => { + beforeEach(() => setupMenu()); + + it('should select an item on click', () => { + spyOn(fixture.componentInstance, 'itemSelected'); + click(getTrigger()); + click(getItem('Apple')!); + expect(fixture.componentInstance.itemSelected).toHaveBeenCalledWith('Apple'); + }); + }); }); describe('Menu Bar Pattern', () => { @@ -987,7 +998,7 @@ class StandaloneMenuExample { template: ` -
+
Apple
Banana
@@ -1007,7 +1018,9 @@ class StandaloneMenuExample { `, imports: [Menu, MenuItem, MenuTrigger, MenuContent], }) -class MenuTriggerExample {} +class MenuTriggerExample { + itemSelected(value: string) {} +} @Component({ template: ` diff --git a/src/aria/private/menu/menu.ts b/src/aria/private/menu/menu.ts index 6ad86e70ae2a..04f3449d7025 100644 --- a/src/aria/private/menu/menu.ts +++ b/src/aria/private/menu/menu.ts @@ -357,26 +357,21 @@ export class MenuPattern { /** Submits the menu. */ submit(item = this.inputs.activeItem()) { - const root = this.root(); - - if (item && !item.disabled()) { - const isMenu = root instanceof MenuPattern; - const isMenuBar = root instanceof MenuBarPattern; - const isMenuTrigger = root instanceof MenuTriggerPattern; - - if (!item.submenu() && isMenuTrigger) { - root.close({refocus: true}); - } + if (!item || item.disabled() || item.submenu()) { + return; + } - if (!item.submenu() && isMenuBar) { - root.close(); - root?.inputs.itemSelected?.(item.value()); - } + const root = this.root(); - if (!item.submenu() && isMenu) { - root.inputs.activeItem()?.close({refocus: true}); - root?.inputs.itemSelected?.(item.value()); - } + if (root instanceof MenuTriggerPattern) { + root.close({refocus: true}); + root?.inputs.menu()?.inputs.itemSelected?.(item.value()); + } else if (root instanceof MenuBarPattern) { + root.close(); + root?.inputs.itemSelected?.(item.value()); + } else if (root instanceof MenuPattern) { + root.inputs.activeItem()?.close({refocus: true}); + root?.inputs.itemSelected?.(item.value()); } }