angular/components · warning
Detected a matBadge on an "aria-hidden" "<mat-icon>". Consid
Error message
Detected a matBadge on an "aria-hidden" "<mat-icon>". Consider setting aria-hidden="false" in order to surface the information assistive technology.
What it means
A `matBadge` was placed on a `<mat-icon>` that has `aria-hidden="true"`. Because mat-icon hides itself from assistive technology by default, the badge content (like a notification count) would be invisible to screen readers. The badge directive warns in dev mode after view init and suggests explicitly exposing the icon.
Source
Thrown at src/material/badge/badge.ts:232
this._badgeElement = this._createBadgeElement();
this._updateRenderedContent(this.content);
}
this._isInitialized = true;
}
ngAfterViewInit() {
if (typeof ngDevMode === 'undefined' || ngDevMode) {
const nativeElement = this._elementRef.nativeElement;
// Heads-up for developers to avoid putting matBadge on <mat-icon>
// as it is aria-hidden by default docs mention this at:
// https://material.angular.dev/components/badge/overview#accessibility
if (
nativeElement.tagName.toLowerCase() === 'mat-icon' &&
nativeElement.getAttribute('aria-hidden') === 'true'
) {
console.warn(
`Detected a matBadge on an "aria-hidden" "<mat-icon>". ` +
`Consider setting aria-hidden="false" in order to surface the information assistive technology.` +
`\n${nativeElement.outerHTML}`,
);
}
}
}
ngOnDestroy() {
// ViewEngine only: when creating a badge through the Renderer, Angular remembers its index.
// We have to destroy it ourselves, otherwise it'll be retained in memory.
if (this._renderer.destroyNode) {
this._renderer.destroyNode(this._badgeElement);
this._inlineBadgeDescription?.remove();
}
this._ariaDescriber.removeDescription(this._elementRef.nativeElement, this.description);
}View on GitHub (pinned to 0411926e7d)
Solutions
- Set `aria-hidden="false"` on the mat-icon so the badge is announced.
- Better: give the badge meaning via `matBadgeDescription`, e.g. `matBadgeDescription="3 unread messages"`.
- Or put the accessible label on the parent button and keep the icon hidden, ensuring the count is conveyed elsewhere.
Example fix
<!-- before --> <mat-icon matBadge="5" aria-hidden="true">mail</mat-icon> <!-- after --> <mat-icon matBadge="5" matBadgeDescription="5 unread messages" aria-hidden="false">mail</mat-icon>
Defensive patterns
Strategy: validation
Validate before calling
const el = iconEl.nativeElement;
if (el.hasAttribute('matBadge') && el.getAttribute('aria-hidden') === 'true') {
console.warn('Badge on aria-hidden icon; set aria-hidden="false" or add matBadgeDescription.');
} Prevention
- Always pair matBadge with matBadgeDescription for accessible text.
- Avoid blanket aria-hidden="true" on mat-icon when it hosts meaningful content.
- Lint templates for matBadge + aria-hidden combos.
When it happens
Trigger: Template like `<mat-icon matBadge="3" aria-hidden="true">mail</mat-icon>` — the directive's `ngAfterViewInit` checks the host's tag name and `aria-hidden` attribute; also triggered when `aria-hidden="true"` is set via host binding on mat-icon.
Common situations: Notification badge on an icon button; developers add `aria-hidden="true"` to mat-icon to silence icon announcements without realizing the badge carries meaningful info.
Related errors
- Cannot retrieve popup content because the combobox is closed
- Unable to retrieve options for autocomplete. Autocomplete pa
- Unable to retrieve option groups for autocomplete. Autocompl
- Unsupported MatButton appearance "${appearance}"
- Cannot begin editing a chip that is not editable.
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/006e85d427fa5c17.
Report an issue: GitHub.