Skip to content

Commit 4897366

Browse files
committed
fix(aria/menu): do not set default aria-label (angular#33202)
This is something that came up in an internal app: by default we were setting `aria-label` to the value of the menu item. This both prevents users from setting their own `aria-label` and is redundant since the item would usually have some content. Fixes angular#32893. (cherry picked from commit 4d045b8)
1 parent a6c5b72 commit 4897366

2 files changed

Lines changed: 79 additions & 63 deletions

File tree

src/aria/menu/menu-item.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import type {MenuBar} from './menu-bar';
2121
*
2222
* ```html
2323
* <div ngMenu (itemSelected)="doAction()">
24-
* <div ngMenuItem >Action Item</div>
24+
* <div ngMenuItem>Action Item</div>
2525
* <div ngMenuItem [submenu]="anotherMenu">Submenu Trigger</div>
2626
* </div>
2727
* ```
@@ -39,7 +39,6 @@ import type {MenuBar} from './menu-bar';
3939
'(focusin)': '_pattern.onFocusIn()',
4040
'[attr.tabindex]': '_pattern.tabIndex()',
4141
'[attr.data-active]': 'active()',
42-
'[attr.aria-label]': 'value()',
4342
'[attr.aria-haspopup]': 'hasPopup()',
4443
'[attr.aria-expanded]': 'expanded()',
4544
'[attr.aria-disabled]': '_pattern.disabled()',
@@ -56,7 +55,7 @@ export class MenuItem<V> {
5655
/** The unique ID of the menu item. */
5756
readonly id = input(inject(_IdGenerator).getId('ng-menu-item-', true));
5857

59-
/** The value of the menu item, used as the default aria-label */
58+
/** The value of the menu item. */
6059
readonly value = input.required<V>();
6160

6261
/** Whether the menu item is disabled. */

src/aria/menu/menu.spec.ts

Lines changed: 77 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -450,14 +450,25 @@ describe('Standalone Menu Pattern', () => {
450450
});
451451

452452
it('should not reset default state on hover triggers expansion', async () => {
453-
TestBed.configureTestingModule({});
454453
fixture = TestBed.createComponent(StandaloneMenuExample);
455454
fixture.detectChanges();
456455

457456
const berries = getItem('Berries');
458457
await mouseover(berries!);
459458
expect(berries?.getAttribute('data-active')).toBe('true');
460459
});
460+
461+
it('should be able to set an aria-label on a menu item', async () => {
462+
fixture = TestBed.createComponent(StandaloneMenuExample);
463+
fixture.detectChanges();
464+
465+
const item = getItem('Apple');
466+
expect(item?.getAttribute('aria-label')).toBeFalsy();
467+
468+
fixture.componentInstance.firstItemAriaLabel.set('Apple item label');
469+
fixture.detectChanges();
470+
expect(item?.getAttribute('aria-label')).toBe('Apple item label');
471+
});
461472
});
462473

463474
describe('Menu Trigger Pattern', () => {
@@ -970,51 +981,57 @@ describe('Menu Bar Pattern', () => {
970981

971982
@Component({
972983
template: `
973-
<div ngMenu [expansionDelay]="0" (itemSelected)="itemSelected($event)">
974-
<ng-template ngMenuContent>
975-
<div ngMenuItem value='Apple' searchTerm='Apple'>Apple</div>
976-
<div ngMenuItem value='Banana' searchTerm='Banana'>Banana</div>
977-
<div ngMenuItem value='Berries' searchTerm='Berries' [submenu]="berriesMenu">Berries</div>
978-
979-
<div ngMenu [expansionDelay]="0" #berriesMenu="ngMenu">
984+
<div ngMenu [expansionDelay]="0" (itemSelected)="itemSelected($event)">
980985
<ng-template ngMenuContent>
981-
<div ngMenuItem value='Blueberry' searchTerm='Blueberry'>Blueberry</div>
982-
<div ngMenuItem value='Blackberry' searchTerm='Blackberry'>Blackberry</div>
983-
<div ngMenuItem value='Strawberry' searchTerm='Strawberry'>Strawberry</div>
986+
<div
987+
ngMenuItem
988+
value='Apple'
989+
searchTerm='Apple'
990+
[attr.aria-label]="firstItemAriaLabel()">Apple</div>
991+
<div ngMenuItem value='Banana' searchTerm='Banana'>Banana</div>
992+
<div ngMenuItem value='Berries' searchTerm='Berries' [submenu]="berriesMenu">Berries</div>
993+
994+
<div ngMenu [expansionDelay]="0" #berriesMenu="ngMenu">
995+
<ng-template ngMenuContent>
996+
<div ngMenuItem value='Blueberry' searchTerm='Blueberry'>Blueberry</div>
997+
<div ngMenuItem value='Blackberry' searchTerm='Blackberry'>Blackberry</div>
998+
<div ngMenuItem value='Strawberry' searchTerm='Strawberry'>Strawberry</div>
999+
</ng-template>
1000+
</div>
1001+
1002+
<div ngMenuItem value='Cherry' searchTerm='Cherry' [disabled]="true">Cherry</div>
9841003
</ng-template>
9851004
</div>
986-
987-
<div ngMenuItem value='Cherry' searchTerm='Cherry' [disabled]="true">Cherry</div>
988-
</ng-template>
989-
</div>
9901005
`,
9911006
imports: [Menu, MenuItem, MenuContent],
9921007
})
9931008
class StandaloneMenuExample {
1009+
firstItemAriaLabel = signal<string | null>(null);
1010+
9941011
itemSelected(value: string) {}
9951012
}
9961013

9971014
@Component({
9981015
template: `
999-
<button ngMenuTrigger [menu]="menu">Open menu</button>
1016+
<button ngMenuTrigger [menu]="menu">Open menu</button>
10001017
1001-
<div ngMenu [expansionDelay]="0" #menu="ngMenu" (itemSelected)="itemSelected($event)">
1002-
<ng-template ngMenuContent>
1003-
<div ngMenuItem value='Apple' searchTerm='Apple'>Apple</div>
1004-
<div ngMenuItem value='Banana' searchTerm='Banana'>Banana</div>
1005-
<div ngMenuItem value='Berries' searchTerm='Berries' [submenu]="berriesMenu">Berries</div>
1006-
1007-
<div ngMenu [expansionDelay]="0" #berriesMenu="ngMenu">
1018+
<div ngMenu [expansionDelay]="0" #menu="ngMenu" (itemSelected)="itemSelected($event)">
10081019
<ng-template ngMenuContent>
1009-
<div ngMenuItem value='Blueberry' searchTerm='Blueberry'>Blueberry</div>
1010-
<div ngMenuItem value='Blackberry' searchTerm='Blackberry'>Blackberry</div>
1011-
<div ngMenuItem value='Strawberry' searchTerm='Strawberry'>Strawberry</div>
1020+
<div ngMenuItem value='Apple' searchTerm='Apple'>Apple</div>
1021+
<div ngMenuItem value='Banana' searchTerm='Banana'>Banana</div>
1022+
<div ngMenuItem value='Berries' searchTerm='Berries' [submenu]="berriesMenu">Berries</div>
1023+
1024+
<div ngMenu [expansionDelay]="0" #berriesMenu="ngMenu">
1025+
<ng-template ngMenuContent>
1026+
<div ngMenuItem value='Blueberry' searchTerm='Blueberry'>Blueberry</div>
1027+
<div ngMenuItem value='Blackberry' searchTerm='Blackberry'>Blackberry</div>
1028+
<div ngMenuItem value='Strawberry' searchTerm='Strawberry'>Strawberry</div>
1029+
</ng-template>
1030+
</div>
1031+
1032+
<div ngMenuItem value='Cherry' searchTerm='Cherry'>Cherry</div>
10121033
</ng-template>
10131034
</div>
1014-
1015-
<div ngMenuItem value='Cherry' searchTerm='Cherry'>Cherry</div>
1016-
</ng-template>
1017-
</div>
10181035
`,
10191036
imports: [Menu, MenuItem, MenuTrigger, MenuContent],
10201037
})
@@ -1024,36 +1041,36 @@ class MenuTriggerExample {
10241041

10251042
@Component({
10261043
template: `
1027-
<div ngMenuBar>
1028-
<div ngMenuItem value='File' searchTerm='File'>File</div>
1029-
<div ngMenuItem value='Edit' searchTerm='Edit' [submenu]="editMenu">Edit</div>
1030-
1031-
<div ngMenu [expansionDelay]="0" #editMenu="ngMenu">
1032-
<ng-template ngMenuContent>
1033-
<div ngMenuItem value='Undo' searchTerm='Undo'>Undo</div>
1034-
<div ngMenuItem value='Redo' searchTerm='Redo'>Redo</div>
1035-
</ng-template>
1036-
</div>
1037-
1038-
<div ngMenuItem [submenu]="viewMenu" value='View' searchTerm='View'>View</div>
1039-
1040-
<div ngMenu [expansionDelay]="0" #viewMenu="ngMenu">
1041-
<ng-template ngMenuContent>
1042-
<div ngMenuItem value='Zoom In' searchTerm='Zoom In'>Zoom In</div>
1043-
<div ngMenuItem value='Zoom Out' searchTerm='Zoom Out'>Zoom Out</div>
1044-
<div ngMenuItem value='Full Screen' searchTerm='Full Screen'>Full Screen</div>
1045-
</ng-template>
1046-
</div>
1047-
1048-
<div ngMenuItem [submenu]="helpMenu" value='Help' searchTerm='Help'>Help</div>
1049-
1050-
<div ngMenu [expansionDelay]="0" #helpMenu="ngMenu">
1051-
<ng-template ngMenuContent>
1052-
<div ngMenuItem value='Documentation' searchTerm='Documentation'>Documentation</div>
1053-
<div ngMenuItem value='About' searchTerm='About'>About</div>
1054-
</ng-template>
1055-
</div>
1056-
</div>
1044+
<div ngMenuBar>
1045+
<div ngMenuItem value='File' searchTerm='File'>File</div>
1046+
<div ngMenuItem value='Edit' searchTerm='Edit' [submenu]="editMenu">Edit</div>
1047+
1048+
<div ngMenu [expansionDelay]="0" #editMenu="ngMenu">
1049+
<ng-template ngMenuContent>
1050+
<div ngMenuItem value='Undo' searchTerm='Undo'>Undo</div>
1051+
<div ngMenuItem value='Redo' searchTerm='Redo'>Redo</div>
1052+
</ng-template>
1053+
</div>
1054+
1055+
<div ngMenuItem [submenu]="viewMenu" value='View' searchTerm='View'>View</div>
1056+
1057+
<div ngMenu [expansionDelay]="0" #viewMenu="ngMenu">
1058+
<ng-template ngMenuContent>
1059+
<div ngMenuItem value='Zoom In' searchTerm='Zoom In'>Zoom In</div>
1060+
<div ngMenuItem value='Zoom Out' searchTerm='Zoom Out'>Zoom Out</div>
1061+
<div ngMenuItem value='Full Screen' searchTerm='Full Screen'>Full Screen</div>
1062+
</ng-template>
1063+
</div>
1064+
1065+
<div ngMenuItem [submenu]="helpMenu" value='Help' searchTerm='Help'>Help</div>
1066+
1067+
<div ngMenu [expansionDelay]="0" #helpMenu="ngMenu">
1068+
<ng-template ngMenuContent>
1069+
<div ngMenuItem value='Documentation' searchTerm='Documentation'>Documentation</div>
1070+
<div ngMenuItem value='About' searchTerm='About'>About</div>
1071+
</ng-template>
1072+
</div>
1073+
</div>
10571074
`,
10581075
imports: [Menu, MenuBar, MenuItem, MenuContent],
10591076
})

0 commit comments

Comments
 (0)