components: Adding panelClass to mat-menu does nothing

Bug:

Adding panelClass to mat-menu does nothing. The problem is that material menu gets rendered using cdk-overlay-pane, which is outside of the component and imposible to style without using ::ng-deep, which interferes with other components using overlay panel.

What is the expected behavior?

Accoring to documentation:

@Input('class')
panelClass: string

This method takes classes set on the host mat-menu element and applies them on the menu template that displays in the overlay container. Otherwise, it's difficult to style the containing menu from outside the component.

Example of non-working code:

<div class="container" [matMenuTriggerFor]="avatarMenu" matTooltip="{{account?.tenantCode}}">
  <span [ngClass]="serverIsReachable ? 'avatar' : 'offline'"></span>
  <div class="account" *ngIf="serverIsReachable">
      <span class="name">{{account?.firstName + ' ' + account?.lastName}}</span>
      <span class="email">{{account?.email}}</span>
  </div>
  <div class="account" *ngIf="!serverIsReachable">
    <span>{{'server-is-unreachable' | translate}}</span>
  </div>
</div>
<mat-menu #avatarMenu="matMenu" yPosition="below" panelClass="custom" [overlapTrigger]="false">
  <div class="settings">
    <label>{{'language'|translate}}</label>
    <div class="languages">
      <span [ngClass]="{ 'sel': trans.currentLang === 'sr' }" (click)="setLang('sr')">SRP</span>
      <span [ngClass]="{ 'sel': trans.currentLang === 'en' }" (click)="setLang('en')">ENG</span>
     </div>
  </div>
  <button mat-menu-item class="logout" (click)="logout()">
    <mat-icon>power_settings_new</mat-icon>
    <span>{{'logout'|translate}}</span>
  </button>
</mat-menu>

What is the current behavior?

Inspecting HTML tree, no classes were applied to any element, even though panelClass property was set on mat-menu component.

What are the steps to reproduce?

Check the info given above

What is the use-case or motivation for changing an existing behavior?

I want to set position and width of overlay element rendering menu contents.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Linux Mint 18.3 Angular 5.2.8 Angular Material 5.2.3 Typescript 2.7.1

Is there anything else we should know?

I know that people reported similar issue earlier, but there wasn’t any viable explanation or solution given to it.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 7
  • Comments: 26 (2 by maintainers)

Most upvoted comments

try to use with

::ng-deep .custom {
 //whatever your rules
}

using the “class” input does the job, but this is still a bug, or at least the API documentation is misleading. This bug should not have been closed imho.

The property on the menu is called panelClass, but the Angular input is actually class (source). Whatever class you set on the mat-menu will be proxied to the overlay.

Consider should clearly state in official doc, else people might use “panelClass” and lead to the confusion.

hey all, how do we add custom classes to the mat-menu?

I have: .mat-menu-panel .custom { background-color: darkgrey; border-radius: 0px; } in my global styles file.

And I have <mat-menu #appMenu="matMenu" [class]="custom" [overlapTrigger]="false"> also.

But, the custom styles aren’t being applied. Am I doing something wrong? I’ve also tried to add .cdk-overlay-pane into the global style but that didn’t work either.

I created a small example in Stackblitz to demonstrate the not working class. Feel free to change it. https://stackblitz.com/edit/angular-jrdttp

@crisbeto can you please take a look at this issue? This should not be closed by reports in this thread, as applying the class property is not only misleading in the documentation, but also, it is not working either.

@Kempo you can turn off encapsulation on your component

@Component({ selector: 'my-navbar', templateUrl: './navbar.component.html', styleUrls: ['./navbar.component.scss'], encapsulation: ViewEncapsulation.None })

but make sure you scope your styles, otherwise, this will affect other components

@MyracleDesign I created a small example in Stackblitz too. It’s working fine.
https://stackblitz.com/edit/angular-p6m8x3

try to use with

::ng-deep .custom {
 //whatever your rules
}

Keep the ::ng-deep part, but when you put your class in square brackets, it needs to have single quotes inside double quotes, such as:

[class]=“‘custom’” This works.

[class]=“custom” This does not work. Notice the single quotes inside double quotes above which works.

try without space between .mat-menu-panel and .custom

.mat-menu-panel.custom { background-color: darkgrey; border-radius: 0px; }