A directive is a class that Angular attaches to an element (or an <ng-template>) to add behavior, change styling, or control whether a chunk of template exists at all. The senior angle is not only naming structural vs attribute directives, but also knowing when to mention TemplateRef/ViewContainerRef, what the * rewrite actually changes, and when an attribute directive is the safer answer because you need to preserve state.
Use this Angular interview question to rehearse a quick answer, common mistake, follow-up, and production pitfall.
Angular directives: structural vs attribute vs components — and what the * syntax really doesFrontend interview answer
This Angular interview question tests whether you can explain Angular directives in production: structural vs attribute, * syntax, and when TemplateRef matters, connect it to production trade-offs, and handle common follow-up questions.
- Angular directives in production: structural vs attribute, * syntax, and when TemplateRef matters explanation without falling back to memorized docs wording
- Directives and Templates reasoning, edge cases, and production failure modes
- How you would answer the most likely Angular interview follow-up
Core idea
A directive is a class that Angular instantiates when it matches a selector in a template. The directive can:
• add behavior (listen to events, update host properties)
• change styling (classes/styles/attributes)
• control the DOM tree by creating/destroying embedded views (structural directives).
Category | What it does | How it shows up | Typical examples |
|---|---|---|---|
Component | A directive with its own template. | Used as an element/tag. |
|
Attribute directive | Changes host element behavior/appearance without changing DOM structure. | Used as an attribute selector. |
|
Structural directive | Adds/removes a block of template by creating/destroying an embedded view. | Usually appears with |
|
What the * really means (microsyntax)* is just syntax sugar. Angular rewrites it into an <ng-template> and binds inputs to the directive on that template.
<!-- Shorthand -->
<div *ngIf="isAdmin">Admin</div>
<!-- Rough desugaring -->
<ng-template [ngIf]="isAdmin">
<div>Admin</div>
</ng-template>
<!-- With else -->
<div *ngIf="isAdmin; else notAdmin">Admin</div>
<ng-template #notAdmin>Not admin</ng-template>
Structural directives are special because… | Concrete consequence |
|---|---|
They operate on | They can create/destroy DOM, component instances, listeners, and run |
Only one | Because the host becomes an |
Custom attribute directive (typical interview example)
Use HostBinding/HostListener (or Renderer2) to affect the host. Avoid direct DOM where possible (SSR/testing safety).
import { Directive, HostBinding, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHighlight]',
standalone: true
})
export class HighlightDirective {
@Input() appHighlight = 'yellow';
@HostBinding('style.backgroundColor') private bg = '';
@HostListener('mouseenter') onEnter() {
this.bg = this.appHighlight;
}
@HostListener('mouseleave') onLeave() {
this.bg = '';
}
}
<p [appHighlight]="'gold'">Hover me</p>
Attribute directives do not wrap the template
That is the practical contrast with structural directives. An attribute directive keeps the same host element alive and just changes host behavior or styling. If the requirement is “highlight, disable, annotate, or listen,” you usually stay in attribute-directive territory and do not need to bring up TemplateRef/ViewContainerRef.
Custom structural directive (the “real” senior signal)
Structural directives control a template block. They inject TemplateRef (what to render) and ViewContainerRef (where to render).
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;
}
}
}
<div *appIf="isVisible">Visible</div>
<!-- desugars to -->
<ng-template [appIf]="isVisible">
<div>Visible</div>
</ng-template>
Interview calibration
If the question is just “what is a directive?”, stop at the three categories. Bring up TemplateRef/ViewContainerRef only when they ask about * syntax, custom structural directives, or why *ngIf destroys component state while an attribute directive does not.
Pitfall | What goes wrong | Better approach |
|---|---|---|
Direct DOM mutation in directives | Breaks SSR/testing; can bypass Angular rendering assumptions | Prefer HostBinding/HostListener or Renderer2; keep DOM work minimal |
Using structural directive when you need state preserved | It destroys/recreates component instances (state resets, subscriptions re-run) | Use |
Multiple | Template rewrite conflict | Wrap with |
Heavy work in directives without OnPush-friendly patterns | Unnecessary change detection / jank in large views | Keep directives small; push heavy logic to services/facades; use async/signal patterns |
Interview one-liners to say |
|---|
“Components are directives with templates; attribute directives modify the host; structural directives create/destroy embedded views.” |
“The * is syntax sugar for <ng-template> + directive inputs.” |
“Structural directives use TemplateRef and ViewContainerRef to manage embedded views.” |
“Prefer HostBinding/HostListener (or Renderer2) over direct DOM access.” |
Directives are Angular’s way to attach behavior to templates. Attribute directives change an existing element; structural directives change the rendered tree by creating/destroying embedded views; components are directives with templates. The key senior detail: * desugars into <ng-template>, and structural directives are basically TemplateRef + ViewContainerRef orchestration.
Use this as one explanation rep, then continue with the Angular interview questions cluster or a guided prep path.