components icon indicating copy to clipboard operation
components copied to clipboard

bug(Menu): Wrapping Menu in your own component breaks focusFirstItem

Open nawlbergs opened this issue 3 years ago • 1 comments
trafficstars

Is this a regression?

  • [ ] Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

In the example below...

  1. focus on the menu trigger (the button) then hit Enter on keyboard...
  2. the menu.js code runs the focusFirstItem method..
  3. this._directDescendantItems is empty... and thus keyboard navigation breaks on the dropdown breaks

BROKEN EXAMPLE (pass the values of dropdown from parent component):

@Component({
  selector: 'app-dropdown',
  template: `
    <button [matMenuTriggerFor]="dd">{{label}}</button>
    <mat-menu #dd="matMenu">
      <ng-content></ng-content>
    </mat-menu>
  `,
  ...

parent component:

<app-dropdown label="My Dropdown">
   <button mat-menu-item>Settings</button>
   <button mat-menu-item>Log off</button>
</app-dropdown>

Hard-coding things there works fine (obviously):

@Component({
  selector: 'app-dropdown',
  template: `
    <button [matMenuTriggerFor]="dd">{{label}}</button>
    <mat-menu #dd="matMenu">
       <button mat-menu-item>Settings</button>
       <button mat-menu-item>Log off</button>
    </mat-menu>
  `,

this works

Reproduction

Steps to reproduce:

  1. wrapper menu with component using slots (content projection)
  2. use keyboard to open menu

Expected Behavior

Opening menu with keyboard would focus first menu-item

Actual Behavior

Opening menu with keyboard fails to focus menu items

Environment

  • Angular: 14.0.4
  • CDK/Material: 14.0.4
  • Browser(s): Chrome Latest (103)
  • Operating System (e.g. Windows, macOS, Ubuntu): Windows 10

nawlbergs avatar Jul 22 '22 00:07 nawlbergs

Ty for reporting, @nawlbergs

Could you please provide a stackblitz reproduction of the issue? -Zach

zarend avatar Jul 26 '22 01:07 zarend

This won't work, because mat-menu uses a ContentChildren query to pick up the items that have been projected. The query isn't going to find the items if they're coming in from another component.

crisbeto avatar Aug 22 '22 09:08 crisbeto

hurmph...

nawlbergs avatar Aug 22 '22 15:08 nawlbergs

We are facing the same problem. Is there a workaround for this?

marcel-goldammer avatar Sep 12 '22 07:09 marcel-goldammer

@zarend This is a working Stackblitz for reproduction: https://stackblitz.com/edit/angular-ivy-r2kuph

marcel-goldammer avatar Sep 12 '22 08:09 marcel-goldammer

@marcel-goldammer What is your use case? If you just have a wrapper component to provide a reusable menu trigger button, you can move the <mat-menu> out of the wrapper into the app component and use @ViewChild() in the wrapper component to connect the trigger button with the menu. A bit more work in the app component (one additional element) but the button + connecting it is still in the wrapper component...

rothsandro avatar Sep 12 '22 09:09 rothsandro

@rothsandro Thanks for your reply!

I added an example with our specific use case to that Stackblitz above. We have custom components with mat-menu-items inside. But the behavior (and maybe the cause to the problem) is exactly the same. When I open the menu using my keyboard it won't focus the first item.

marcel-goldammer avatar Sep 12 '22 10:09 marcel-goldammer

@marcel-goldammer Ah, the menu items are in a third component. Yes, that doesn't work. menu + menu item must be in the same component, only the button can be extracted and reused :(

rothsandro avatar Sep 12 '22 18:09 rothsandro

Thanks for the reply. That is somewhat bad for us, but now I know, that we have to deal with those circumstances.

marcel-goldammer avatar Sep 12 '22 18:09 marcel-goldammer

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.