Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix(material/menu): render backdrop for context menu if explicitly op…
…ted in

When we introduced context menus, we disabled backdrops on them in order to mimic the native behavior where right clicking somewhere else moves the menu there. This seems to not be desirable for some users so these changes add some logic to enable the backdrop if the user explicitly requested it.

Fixes #32350.
  • Loading branch information
crisbeto committed Feb 24, 2026
commit 2c0fa44ff373a6d63ef04dabe09fcba7bc86d0f7
22 changes: 21 additions & 1 deletion src/material/menu/context-menu-trigger.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Component, signal} from '@angular/core';
import {Component, signal, ViewChild} from '@angular/core';
import {ComponentFixture, fakeAsync, flush, TestBed} from '@angular/core/testing';
import {MatContextMenuTrigger} from './context-menu-trigger';
import {MatMenu} from './menu';
Expand All @@ -16,6 +16,10 @@ describe('context menu trigger', () => {
return document.querySelector('.mat-mdc-menu-panel');
}

function getBackdrop(): HTMLElement | null {
return document.querySelector('.cdk-overlay-backdrop');
}

beforeEach(() => {
fixture = TestBed.createComponent(ContextMenuTest);
fixture.detectChanges();
Expand Down Expand Up @@ -157,6 +161,21 @@ describe('context menu trigger', () => {
fixture.detectChanges();
expect(getMenu()).toBe(null);
});

it('should not create a backdrop for context menu by default', () => {
dispatchMouseEvent(getTrigger(), 'contextmenu', 10, 10);
fixture.detectChanges();
expect(getBackdrop()).toBeFalsy();
expect(getMenu()).toBeTruthy();
});

it('should create a backdrop for context menus if the menu explicitly opted into it', () => {
fixture.componentInstance.menuInstance.hasBackdrop = true;
dispatchMouseEvent(getTrigger(), 'contextmenu', 10, 10);
fixture.detectChanges();
expect(getBackdrop()).toBeTruthy();
expect(getMenu()).toBeTruthy();
});
});

@Component({
Expand Down Expand Up @@ -185,6 +204,7 @@ describe('context menu trigger', () => {
`,
})
class ContextMenuTest {
@ViewChild(MatMenu) menuInstance!: MatMenu;
showTrigger = signal(true);
disabled = signal(false);
opened = jasmine.createSpy('opened');
Expand Down
2 changes: 1 addition & 1 deletion src/material/menu/menu-trigger-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export abstract class MatMenuTriggerBase implements OnDestroy {
overlayConfig.hasBackdrop =
menu.hasBackdrop == null ? !this._triggersSubmenu() : menu.hasBackdrop;
} else {
overlayConfig.hasBackdrop = false;
overlayConfig.hasBackdrop = menu.hasBackdrop ?? false;
}

// We need the `hasAttached` check for the case where the user kicked off a removal animation,
Expand Down
4 changes: 4 additions & 0 deletions src/material/menu/menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ area and will be closed if the user clicks away.
You can set up a `mat-menu` as a context menu by adding the `matContextMenuTriggerFor` directive
to your container and binding it to a menu instance.

Note that by default context menus don't create a backdrop element in order to allow the user to
right click somewhere else. You can opt into the backdrop by explicitly setting
`[hasBackdrop]="true"` on the menu.

<!-- example(context-menu) -->

### Lazy rendering
Expand Down
Loading