Skip to content

Commit ad2baa6

Browse files
authored
fix(material/menu): submenu icon not working in high contrast mode (#23012)
Currently the submenu icon is rendered as a CSS triangle which turns into a rectangle in high contrast mode. These changes resolve the issue by using SVG for the icon instead. Fixes #22944.
1 parent 0b65df0 commit ad2baa6

File tree

9 files changed

+49
-29
lines changed

9 files changed

+49
-29
lines changed

src/material-experimental/mdc-menu/_menu-theme.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
// items so we have to grey them out ourselves.
1919
.mat-mdc-menu-item[disabled] {
2020
&,
21-
&::after,
21+
.mat-mdc-menu-submenu-icon,
2222
.mat-icon-no-color {
2323
@include mdc-theme.prop(color, text-disabled-on-background);
2424
}
@@ -27,7 +27,7 @@
2727
// Since we're creating `mat-icon` and the submenu trigger
2828
// chevron ourselves, we have to handle the color as well.
2929
.mat-mdc-menu-item .mat-icon-no-color,
30-
.mat-mdc-menu-item-submenu-trigger::after {
30+
.mat-mdc-menu-submenu-icon {
3131
@include mdc-theme.prop(color, text-icon-on-background);
3232
}
3333

src/material-experimental/mdc-menu/menu-item.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@
33
[matRippleDisabled]="disableRipple || disabled"
44
[matRippleTrigger]="_getHostElement()">
55
</div>
6+
<svg
7+
*ngIf="_triggersSubmenu"
8+
class="mat-mdc-menu-submenu-icon"
9+
viewBox="0 0 5 10"
10+
focusable="false"><polygon points="0,0 5,5 0,10"/></svg>

src/material-experimental/mdc-menu/menu.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,14 @@ mat-menu {
9898
}
9999
}
100100

101-
// Renders out a chevron on menu items that trigger a sub-menu.
102101
.mat-mdc-menu-item-submenu-trigger {
103102
@include menu-common.item-submenu-trigger(mdc-list.$deprecated-side-padding);
104103
}
105104

105+
.mat-mdc-menu-submenu-icon {
106+
@include menu-common.item-submenu-icon(mdc-list.$deprecated-side-padding);
107+
}
108+
106109
// Increase specificity because ripple styles are part of the `mat-core` mixin and can
107110
// potentially overwrite the absolute position of the container.
108111
.mat-mdc-menu-item .mat-mdc-menu-ripple {

src/material-experimental/mdc-menu/menu.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,7 +2070,9 @@ describe('MDC-based MatMenu', () => {
20702070
const menuItems = overlay.querySelectorAll('[mat-menu-item]');
20712071

20722072
expect(menuItems[0].classList).toContain('mat-mdc-menu-item-submenu-trigger');
2073+
expect(menuItems[0].querySelector('.mat-mdc-menu-submenu-icon')).toBeTruthy();
20732074
expect(menuItems[1].classList).not.toContain('mat-mdc-menu-item-submenu-trigger');
2075+
expect(menuItems[1].querySelector('.mat-mdc-menu-submenu-icon')).toBeFalsy();
20742076
});
20752077

20762078
it('should increase the sub-menu elevation based on its depth', () => {

src/material/core/style/_menu-common.scss

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@use './private';
1+
@use '../../../cdk/a11y';
22
@use './list-common';
33
@use './layout-common';
44

@@ -58,36 +58,34 @@ $icon-margin: 16px !default;
5858
}
5959
}
6060

61-
@mixin item-submenu-trigger($side-padding, $triangle-height: 10px) {
61+
@mixin item-submenu-trigger($side-padding) {
6262
// Increase the side padding to prevent the indicator from overlapping the text.
6363
padding-right: $side-padding * 2;
6464

65-
// Renders a triangle to indicate that the menu item will open a sub-menu.
66-
&::after {
67-
$size: private.private-div($triangle-height, 2);
68-
69-
width: 0;
70-
height: 0;
71-
border-style: solid;
72-
border-width: $size 0 $size $size;
73-
border-color: transparent transparent transparent currentColor;
74-
content: '';
75-
display: inline-block;
76-
position: absolute;
77-
top: 50%;
78-
right: $side-padding;
79-
transform: translateY(-50%);
80-
}
81-
8265
[dir='rtl'] & {
8366
padding-right: $side-padding;
8467
padding-left: $side-padding * 2;
68+
}
69+
}
8570

86-
&::after {
87-
right: auto;
88-
left: $side-padding;
89-
transform: rotateY(180deg) translateY(-50%);
90-
}
71+
@mixin item-submenu-icon($side-padding) {
72+
position: absolute;
73+
top: 50%;
74+
right: $side-padding;
75+
transform: translateY(-50%);
76+
width: 5px;
77+
height: 10px;
78+
fill: currentColor;
79+
80+
[dir='rtl'] & {
81+
right: auto;
82+
left: $side-padding;
83+
transform: translateY(-50%) scaleX(-1);
84+
}
85+
86+
// Fix for Chromium-based browsers blending in the `currentColor` with the background.
87+
@include a11y.high-contrast(active, off) {
88+
fill: CanvasText;
9189
}
9290
}
9391

src/material/menu/_menu-theme.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121

2222
&[disabled] {
2323
&,
24-
&::after,
24+
.mat-menu-submenu-icon,
2525
.mat-icon-no-color {
2626
color: theming.get-color-from-palette($foreground, 'disabled');
2727
}
2828
}
2929
}
3030

3131
.mat-menu-item .mat-icon-no-color,
32-
.mat-menu-item-submenu-trigger::after {
32+
.mat-menu-submenu-icon {
3333
color: theming.get-color-from-palette($foreground, 'icon');
3434
}
3535

src/material/menu/menu-item.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,9 @@
33
[matRippleDisabled]="disableRipple || disabled"
44
[matRippleTrigger]="_getHostElement()">
55
</div>
6+
7+
<svg
8+
*ngIf="_triggersSubmenu"
9+
class="mat-menu-submenu-icon"
10+
viewBox="0 0 5 10"
11+
focusable="false"><polygon points="0,0 5,5 0,10"/></svg>

src/material/menu/menu.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ mat-menu {
7777
@include menu-common.item-submenu-trigger(menu-common.$side-padding);
7878
}
7979

80+
.mat-menu-submenu-icon {
81+
@include menu-common.item-submenu-icon(menu-common.$side-padding);
82+
}
83+
8084
button.mat-menu-item {
8185
width: 100%;
8286
}

src/material/menu/menu.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,7 +2055,9 @@ describe('MatMenu', () => {
20552055
const menuItems = overlay.querySelectorAll('[mat-menu-item]');
20562056

20572057
expect(menuItems[0].classList).toContain('mat-menu-item-submenu-trigger');
2058+
expect(menuItems[0].querySelector('.mat-menu-submenu-icon')).toBeTruthy();
20582059
expect(menuItems[1].classList).not.toContain('mat-menu-item-submenu-trigger');
2060+
expect(menuItems[1].querySelector('.mat-menu-submenu-icon')).toBeFalsy();
20592061
});
20602062

20612063
it('should increase the sub-menu elevation based on its depth', () => {

0 commit comments

Comments
 (0)