angular/components · error · Error

matBadge must be attached to an element node.

Error message

matBadge must be attached to an element node.

What it means

MatBadge is a directive that renders a badge overlay positioned relative to its host element via CSS. It requires _elementRef.nativeElement to be a real DOM element node so it can append the badge element to it. In ngDevMode it throws if the host node is not an ELEMENT_NODE (e.g. a text, comment, or document node).

Source

Thrown at src/material/badge/badge.ts:184

  private _document = inject(DOCUMENT);

  constructor() {
    const config = inject(MAT_BADGE_CONFIG, {optional: true});
    const styleLoader = inject(_CdkPrivateStyleLoader);
    styleLoader.load(_MatBadgeStyleLoader);
    styleLoader.load(_VisuallyHiddenLoader);

    this._color = config?.color || 'primary';
    this.overlap = config?.overlap ?? true;
    this.position = config?.position || 'above after';
    this.size = config?.size || 'medium';

    if (typeof ngDevMode === 'undefined' || ngDevMode) {
      const nativeElement = this._elementRef.nativeElement;

      if (nativeElement.nodeType !== nativeElement.ELEMENT_NODE) {
        throw Error('matBadge must be attached to an element node.');
      }
    }
  }

  /** Whether the badge is above the host or not */
  isAbove(): boolean {
    return this.position.indexOf('below') === -1;
  }

  /** Whether the badge is after the host or not */
  isAfter(): boolean {
    return this.position.indexOf('before') === -1;
  }

  /**
   * Gets the element into which the badge's content is being rendered. Undefined if the element
   * hasn't been created (e.g. if the badge doesn't have content).
   */

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Move matBadge to a real HTML element (div, span, button, mat-icon, etc.).
  2. If wrapping ng-container content, add a wrapper element and put matBadge on it.
  3. Ensure the element the directive is on actually renders an element node in the DOM (not a template/comment placeholder).

Example fix

// before
<ng-container matBadge="3">Items</ng-container>
// after
<span matBadge="3">Items</span>
Defensive patterns

Strategy: validation

Validate before calling

// before applying the directive, ensure the target is a real element
const el = document.querySelector('.toolbar-title');
if (!el || el.nodeType !== Node.ELEMENT_NODE) {
  throw new Error('matBadge target must be an element node');
}

Type guard

function isElementNode(n: Node): n is HTMLElement {
  return n.nodeType === Node.ELEMENT_NODE;
}

Try / catch

try {
  renderTemplate(); // template with matBadge
} catch (e) {
  if (e instanceof Error && e.message.includes('matBadge must be attached to an element node')) {
    logger.warn('matBadge applied to non-element node; fix template');
  } else { throw e; }
}

Prevention

When it happens

Trigger: Applying matBadge to something that produces a non-element node as the directive host — e.g. placing matBadge on <ng-container> or an attribute-style usage that resolves to a comment/text node.

Common situations: Developers try to hang a badge on ng-container, ng-template, or an SVG/text node; or a structural wrapper makes the directive host a comment node. Also common when porting templates from component selectors that render as comments (e.g. router-outlet-like placeholders).

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/6ed15b79f2e1c035. Report an issue: GitHub.