diff --git a/src/lib/menu/menu-item.ts b/src/lib/menu/menu-item.ts index c19a40b0184..d97367b69ab 100644 --- a/src/lib/menu/menu-item.ts +++ b/src/lib/menu/menu-item.ts @@ -15,6 +15,7 @@ import { ViewEncapsulation, Inject, Optional, + Input, } from '@angular/core'; import { CanDisable, CanDisableCtor, @@ -42,7 +43,7 @@ export const _MatMenuItemMixinBase: CanDisableRippleCtor & CanDisableCtor & type exportAs: 'matMenuItem', inputs: ['disabled', 'disableRipple'], host: { - 'role': 'menuitem', + '[attr.role]': 'role', 'class': 'mat-menu-item', '[class.mat-menu-item-highlighted]': '_highlighted', '[class.mat-menu-item-submenu-trigger]': '_triggersSubmenu', @@ -59,6 +60,9 @@ export const _MatMenuItemMixinBase: CanDisableRippleCtor & CanDisableCtor & type export class MatMenuItem extends _MatMenuItemMixinBase implements FocusableOption, CanDisable, CanDisableRipple, OnDestroy { + /** ARIA role for the menu item. */ + @Input() role: 'menuitem' | 'menuitemradio' | 'menuitemcheckbox' = 'menuitem'; + private _document: Document; /** Stream that emits when the menu item is hovered. */ diff --git a/src/lib/menu/menu.spec.ts b/src/lib/menu/menu.spec.ts index 87c25446cbe..81415a13364 100644 --- a/src/lib/menu/menu.spec.ts +++ b/src/lib/menu/menu.spec.ts @@ -385,6 +385,30 @@ describe('MatMenu', () => { expect(role).toBe('menu', 'Expected panel to have the "menu" role.'); }); + it('should set the "menuitem" role on the items by default', () => { + const fixture = createComponent(SimpleMenu, [], [FakeIcon]); + fixture.detectChanges(); + fixture.componentInstance.trigger.openMenu(); + fixture.detectChanges(); + + const items = Array.from(overlayContainerElement.querySelectorAll('.mat-menu-item')); + + expect(items.length).toBeGreaterThan(0); + expect(items.every(item => item.getAttribute('role') === 'menuitem')).toBe(true); + }); + + it('should be able to set an alternate role on the menu items', () => { + const fixture = createComponent(MenuWithCheckboxItems); + fixture.detectChanges(); + fixture.componentInstance.trigger.openMenu(); + fixture.detectChanges(); + + const items = Array.from(overlayContainerElement.querySelectorAll('.mat-menu-item')); + + expect(items.length).toBeGreaterThan(0); + expect(items.every(item => item.getAttribute('role') === 'menuitemcheckbox')).toBe(true); + }); + it('should not throw an error on destroy', () => { const fixture = createComponent(SimpleMenu, [], [FakeIcon]); expect(fixture.destroy.bind(fixture)).not.toThrow(); @@ -2100,3 +2124,18 @@ class DynamicPanelMenu { @ViewChild('one') firstMenu: MatMenu; @ViewChild('two') secondMenu: MatMenu; } + + +@Component({ + template: ` + + + + + + + ` +}) +class MenuWithCheckboxItems { + @ViewChild(MatMenuTrigger) trigger: MatMenuTrigger; +}