Structural vs Attribute Directives in Angular: what changes the DOM tree (and what does * actually mean)?

LowIntermediateAngular
Preparing for interviews?

Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.

Quick Answer

Structural directives change the rendered template tree by creating/destroying embedded views (real DOM + component instances). Attribute directives do not change the tree; they modify an existing element’s properties/classes/styles/behavior. Key interview nuance: the * syntax is just sugar for <ng-template> + directive inputs. Structural directives change the DOM tree, so test lifecycle, performance, and accessibility side effects.

Answer

Core idea

Structural directives decide whether a block of template exists at all (create/destroy an embedded view). Attribute directives keep the element in place and only change the host element’s behavior/appearance (classes/styles/attrs/listeners).

Aspect

Structural directives

Attribute directives

What they change

The template structure (create/destroy/move embedded views).

The host element (styles/classes/attributes/behavior).

DOM impact

✅ Real DOM nodes and component/directive instances are created/destroyed.

❌ No tree changes; the same element stays in the DOM.

Typical syntax

*ngIf, *ngFor, *ngSwitchCase (microsyntax).

[ngClass], [ngStyle], [class.x], custom attribute directives.

How it works internally

Uses TemplateRef + ViewContainerRef to manage embedded views.

Uses HostBinding/HostListener (or Renderer2) to affect the host.

Lifecycle/state implication

Destroying the view runs ngOnDestroy and resets component state on next show.

State is preserved because the instance isn’t destroyed.

Structural vs attribute directives (interview framing)

The * is syntax sugar

Angular rewrites * into an <ng-template> and attaches the directive there. That’s why structural directives operate on templates (not “just visibility”).

HTML
<!-- Shorthand -->
<div *ngIf="isAdmin">Admin</div>

<!-- Rough desugaring -->
<ng-template [ngIf]="isAdmin">
  <div>Admin</div>
</ng-template>

<!-- Combining multiple conditions: use ng-container -->
<ng-container *ngIf="isAdmin">
  <div *ngFor="let item of items">{{ item }}</div>
</ng-container>
                  

Attribute directive example (preferred pattern)

Attribute directives typically bind to the host element instead of imperatively touching the DOM.

TYPESCRIPT
import { Directive, HostBinding, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  standalone: true
})
export class HighlightDirective {
  @Input() appHighlight = 'gold';

  @HostBinding('style.backgroundColor') private bg = '';

  @HostListener('mouseenter') onEnter() { this.bg = this.appHighlight; }
  @HostListener('mouseleave') onLeave() { this.bg = ''; }
}
                  

Structural directive example (what seniors mention)

Structural directives render a template block by creating/destroying an embedded view via ViewContainerRef.

TYPESCRIPT
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appIf]',
  standalone: true
})
export class AppIfDirective {
  private hasView = false;

  constructor(
    private tpl: TemplateRef<unknown>,
    private vcr: ViewContainerRef
  ) {}

  @Input() set appIf(condition: boolean) {
    if (condition && !this.hasView) {
      this.vcr.createEmbeddedView(this.tpl);
      this.hasView = true;
      return;
    }

    if (!condition && this.hasView) {
      this.vcr.clear();
      this.hasView = false;
    }
  }
}

// usage: <div *appIf="isVisible">...</div>
                  

Gotcha

What happens

What to do instead

“*ngIf just hides it”

False: it destroys/creates the view (state resets, subscriptions re-run).

Use [hidden] / CSS when you must preserve instance state.

Multiple * on one element

Only one structural directive can own the host rewrite to <ng-template>.

Wrap with <ng-container> or split elements.

Direct DOM access in directives

Can break SSR/testing and bypass Angular abstractions.

Prefer HostBinding/HostListener or Renderer2 if needed.

Common interview pitfalls

Practical scenario
Use *ngIf to conditionally render a panel and [ngClass] to style it.

Common pitfalls

      • Assuming structural directives only hide elements (they remove them).
      • Losing component state when DOM nodes are destroyed.
      • Overusing *ngIf for show/hide instead of [hidden].
Trade-off or test tip
Structural directives save work but reset state. Test with toggling and lifecycle hooks.

Summary

Structural directives change the rendered tree by creating/destroying embedded views (real lifecycle + state effects). Attribute directives keep the tree and modify the host element’s behavior/appearance. The * is just sugar for <ng-template> + directive inputs—knowing that is the senior signal.

Similar questions
Guides
22 / 37