Skip to content

Commit 2b08641

Browse files
committed
fix(badge): put matBadgeDescription on host instead of badge element
Fixes a screenreader issue on the mat-badge component where screenreaders did not read the `matBadgeDescription` for badges hosted on `button` elements. Example: ```<button mat-badge="2" matBadgeDescription="2 unread messages">open messages</button>``` As tested on Chromevox with Chrome browser, screenreader reads "open messages" and does *not* read "2 unread messages". Screenreader does not allow navigation to the badge element. This happens because `button`'s are not supposed to have multiple lines. Solution is to align with tooltip by making the badge element aria-hidden and applying the `matBadgeDescription` to the host element.
1 parent 8424209 commit 2b08641

File tree

3 files changed

+12
-15
lines changed

3 files changed

+12
-15
lines changed

src/dev-app/badge/badge-demo.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ <h3>Buttons</h3>
6767
<button mat-raised-button>
6868
<mat-icon matBadge="22" color="accent">home</mat-icon>
6969
</button>
70+
71+
<button mat-button matBadge="11" matBadgeDescription="I've got 11 problems.">
72+
Aria
73+
</button>
7074
</div>
7175

7276
<div class="demo-badge">

src/dev-app/badge/badge-demo.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
margin-bottom: 25px;
33
}
44

5-
.mat-badge {
5+
.mat-badge, .mat-button {
66
margin-right: 22px;
77

88
[dir='rtl'] & {

src/material/badge/badge.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,6 @@ export class MatBadge extends _MatBadgeBase implements OnDestroy, OnChanges, Can
9494
const badgeElement = this._badgeElement;
9595
this._updateHostAriaDescription(newDescription, this._description);
9696
this._description = newDescription;
97-
98-
if (badgeElement) {
99-
newDescription ? badgeElement.setAttribute('aria-label', newDescription) :
100-
badgeElement.removeAttribute('aria-label');
101-
}
10297
}
10398
}
10499
private _description: string;
@@ -160,7 +155,7 @@ export class MatBadge extends _MatBadgeBase implements OnDestroy, OnChanges, Can
160155

161156
if (badgeElement) {
162157
if (this.description) {
163-
this._ariaDescriber.removeDescription(badgeElement, this.description);
158+
this._ariaDescriber.removeDescription(this._elementRef.nativeElement, this.description);
164159
}
165160

166161
// When creating a badge through the Renderer, Angular will keep it in an index.
@@ -197,6 +192,8 @@ export class MatBadge extends _MatBadgeBase implements OnDestroy, OnChanges, Can
197192

198193
// Clear any existing badges which may have persisted from a server-side render.
199194
this._clearExistingBadges(contentClass);
195+
// Hide badge element from screen readers.
196+
badgeElement.setAttribute('aria-hidden', 'true');
200197
badgeElement.setAttribute('id', `mat-badge-content-${this._id}`);
201198
badgeElement.classList.add(contentClass);
202199
badgeElement.textContent = this._stringifyContent();
@@ -205,10 +202,6 @@ export class MatBadge extends _MatBadgeBase implements OnDestroy, OnChanges, Can
205202
badgeElement.classList.add('_mat-animation-noopable');
206203
}
207204

208-
if (this.description) {
209-
badgeElement.setAttribute('aria-label', this.description);
210-
}
211-
212205
this._elementRef.nativeElement.appendChild(badgeElement);
213206

214207
// animate in after insertion
@@ -225,17 +218,17 @@ export class MatBadge extends _MatBadgeBase implements OnDestroy, OnChanges, Can
225218
return badgeElement;
226219
}
227220

228-
/** Sets the aria-label property on the element */
221+
/** Sets the aria-describedby property on the host element */
229222
private _updateHostAriaDescription(newDescription: string, oldDescription: string): void {
230223
// ensure content available before setting label
231-
const content = this._updateTextContent();
224+
this._updateTextContent();
232225

233226
if (oldDescription) {
234-
this._ariaDescriber.removeDescription(content, oldDescription);
227+
this._ariaDescriber.removeDescription(this._elementRef.nativeElement, oldDescription);
235228
}
236229

237230
if (newDescription) {
238-
this._ariaDescriber.describe(content, newDescription);
231+
this._ariaDescriber.describe(this._elementRef.nativeElement, newDescription);
239232
}
240233
}
241234

0 commit comments

Comments
 (0)