Angular Custom Directives

Learn Angular Custom Directives with detailed examples, lifecycle, ElementRef, Renderer2, HostListener, HostBinding, Dependency Injection, standalone directives, enterprise use cases, architecture diagrams, and interview questions.

Angular provides many built-in directives like ngIf, ngFor, ngClass, and ngStyle.

However, enterprise applications often require reusable UI behavior that isn't available out of the box. This is where Custom Directives become extremely useful.

Custom Directives allow developers to:

  • Reuse UI behavior
  • Encapsulate DOM manipulation
  • Improve maintainability
  • Reduce duplicate code
  • Build reusable enterprise components

Custom Directives are a favorite interview topic for Senior Angular Developers, Tech Leads, and Angular Architects.


Table of Contents

  • What are Custom Directives?
  • Types of Directives
  • Attribute Directives
  • Structural Directives
  • Creating Custom Directives
  • HostListener
  • HostBinding
  • Renderer2
  • ElementRef
  • Dependency Injection
  • Standalone Directives
  • Enterprise Examples
  • Performance Best Practices
  • Top 10 Interview Questions
  • Summary

What are Custom Directives?

A Custom Directive is a reusable class that extends the behavior of HTML elements.

Unlike Components, directives do not have their own templates.

They simply modify existing elements.

Examples:

  • Highlight text
  • Change colors
  • Show tooltips
  • Restrict input
  • Auto focus
  • Permission checks
  • Lazy image loading
  • Infinite scrolling

Angular Directive Architecture

flowchart TD

Angular

Angular --> Component

Angular --> AttributeDirective

Angular --> StructuralDirective

Component --> HTML

AttributeDirective --> HTML

StructuralDirective --> HTML

Directive Types

Directive Purpose
Component UI + Template
Attribute Directive Changes appearance/behavior
Structural Directive Changes DOM layout

Attribute Directive Example

flowchart LR

Component

Component --> HighlightDirective

HighlightDirective --> HTML

HTML --> Browser

Creating a Custom Directive

Generate using Angular CLI

ng generate directive highlight

or

ng g d highlight

Basic Highlight Directive

import {
Directive,
ElementRef
} from '@angular/core';

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

constructor(
private element:
ElementRef
){

this.element.nativeElement
.style.backgroundColor='yellow';

}

}

Usage

<p appHighlight>

Highlighted Text

</p>

Output

Yellow Background

Directive Execution Flow

sequenceDiagram

participant Template

participant Directive

participant DOM

participant Browser

Template->>Directive: appHighlight

Directive->>DOM: Modify Element

DOM-->>Browser: Render

Why Renderer2?

Direct DOM manipulation through ElementRef.nativeElement should be minimized because it can make code less portable and harder to test.

Angular recommends Renderer2 for DOM updates.


Using Renderer2

import {
Directive,
ElementRef,
Renderer2
} from '@angular/core';

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

constructor(

private element:ElementRef,

private renderer:Renderer2

){

this.renderer.setStyle(

this.element.nativeElement,

'background',

'yellow'

);

}

}

Advantages

  • Platform independent
  • Better security
  • Easier testing
  • Works with server-side rendering

Renderer2 Architecture

flowchart LR

Directive

Directive --> Renderer2

Renderer2 --> DOM

DOM --> Browser

Using HostListener

HostListener listens to events on the host element.

Example

import {
Directive,
ElementRef,
HostListener,
Renderer2
} from '@angular/core';

@Directive({
selector:'[appHover]',
standalone:true
})
export class HoverDirective{

constructor(

private element:ElementRef,

private renderer:Renderer2

){}

@HostListener('mouseenter')

mouseEnter(){

this.renderer.setStyle(

this.element.nativeElement,

'background',

'lightblue'

);

}

@HostListener('mouseleave')

mouseLeave(){

this.renderer.removeStyle(

this.element.nativeElement,

'background'

);

}

}

Usage

<div appHover>

Move Mouse Here

</div>

Event Flow

flowchart TD

MouseEnter

MouseEnter --> HostListener

HostListener --> Renderer2

Renderer2 --> DOM

Using HostBinding

HostBinding binds properties of the host element.

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

@Directive({
selector:'[appBorder]',
standalone:true
})
export class BorderDirective{

@HostBinding('style.border')

border='2px solid blue';

@HostBinding('style.borderRadius')

radius='8px';

@HostListener('mouseenter')

hover(){

this.border='2px solid red';

}

@HostListener('mouseleave')

leave(){

this.border='2px solid blue';

}

}

HostBinding Architecture

flowchart LR

HostBinding

HostBinding --> ElementStyle

ElementStyle --> Browser

Passing Values to Directives

Directives can receive inputs.

import {
Directive,
ElementRef,
Input,
Renderer2
} from '@angular/core';

@Directive({
selector:'[appColor]',
standalone:true
})
export class ColorDirective{

@Input()

appColor='blue';

constructor(

private element:ElementRef,

private renderer:Renderer2

){}

ngOnInit(){

this.renderer.setStyle(

this.element.nativeElement,

'color',

this.appColor

);

}

}

Usage

<p

[appColor]="'green'">

Angular

</p>

Structural Directive Example

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

@Directive({
selector:'[appIfRole]',
standalone:true
})
export class IfRoleDirective{

constructor(

private template:
TemplateRef<unknown>,

private view:
ViewContainerRef

){}

@Input()

set appIfRole(hasAccess:boolean){

this.view.clear();

if(hasAccess){

this.view.createEmbeddedView(
this.template
);

}

}

}

Usage

<div *appIfRole="isAdmin">

Admin Menu

</div>

Structural Directive Flow

flowchart TD

Condition

Condition --> True

Condition --> False

True --> CreateView

False --> ClearView

Dependency Injection

Directives support Angular Dependency Injection.

Example

@Injectable({
providedIn:'root'
})
export class ThemeService{

currentColor(){

return 'green';

}

}

Directive

constructor(

private theme:
ThemeService,

private renderer:
Renderer2,

private element:
ElementRef

){}

Standalone Directives

Angular supports standalone directives.

@Directive({

selector:'[appFocus]',

standalone:true

})
export class FocusDirective{}

Standalone Component

@Component({
standalone:true,
imports:[FocusDirective]
})
export class HomeComponent{}

Auto Focus Directive

import {
AfterViewInit,
Directive,
ElementRef
} from '@angular/core';

@Directive({
selector:'[appAutoFocus]',
standalone:true
})
export class AutoFocusDirective
implements AfterViewInit{

constructor(
private element:ElementRef
){}

ngAfterViewInit(){

this.element.nativeElement.focus();

}

}

Usage

<input appAutoFocus>

Numbers Only Directive

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

@Directive({
selector:'[appNumbersOnly]',
standalone:true
})
export class NumbersOnlyDirective{

@HostListener('keypress',['$event'])

allowNumbers(event:KeyboardEvent){

const key=event.key;

if(!/[0-9]/.test(key)){

event.preventDefault();

}

}

}

Usage

<input appNumbersOnly>

Enterprise Banking Example

Imagine an online banking application.

Custom Directives:

  • Highlight overdue loans
  • Hide admin menu
  • Restrict account input
  • Auto focus login field
  • Highlight negative balance
  • Copy account number
  • Permission-based rendering
flowchart TD

Dashboard

Dashboard --> HighlightDirective

Dashboard --> PermissionDirective

Dashboard --> AutoFocusDirective

Dashboard --> TooltipDirective

HighlightDirective --> LoanCard

PermissionDirective --> AdminMenu

AutoFocusDirective --> Login

TooltipDirective --> Balance

Performance Best Practices

Practice Benefit
Prefer Renderer2 Platform independence
Keep directives lightweight Faster rendering
Avoid business logic Better separation of concerns
Reuse directives Less duplicate code
Use standalone directives Simpler architecture
Minimize direct DOM access Better compatibility

Common Mistakes

Using ElementRef Excessively

element.nativeElement.style.color='red';

Prefer

renderer.setStyle(...)

Business Logic Inside Directives

Avoid putting API calls or complex business rules inside directives.


Large Directives

Split directives into smaller reusable units.


Memory Leaks

If a directive subscribes to Observables or registers custom listeners, clean them up appropriately (for example, using DestroyRef or lifecycle cleanup).


Advantages

Feature Benefit
Reusable Write once
Cleaner Components Better architecture
Standalone Easy imports
Renderer2 Safe DOM manipulation
HostListener Event handling
HostBinding Dynamic properties
DI Support Reusable services
Lightweight Better performance

Real-World Enterprise Use Cases

Scenario Directive
Banking Permission Directive
HR Employee Highlight
Insurance Policy Status Color
E-Commerce Product Badge
Healthcare Critical Patient Highlight
CRM VIP Customer Highlight
Logistics Shipment Status
Education Grade Highlight

Top 10 Angular Custom Directives Interview Questions

1. What is a Custom Directive?

Answer

A Custom Directive is a reusable Angular class that adds behavior or modifies the appearance of existing DOM elements without having its own template.


2. What are the two major types of directives?

Answer

  • Attribute Directives
  • Structural Directives

3. What is the difference between a Component and a Directive?

Component Directive
Has a template No template
Creates UI Modifies existing UI
Uses @Component Uses @Directive

4. Why is Renderer2 preferred over ElementRef?

Answer

Renderer2 provides a platform-independent and testable way to modify the DOM while reducing direct dependency on browser-specific APIs.


5. What is HostListener?

Answer

@HostListener listens for events on the host element and invokes a method when those events occur.

Example:

@HostListener('click')
onClick() {}

6. What is HostBinding?

Answer

@HostBinding binds a property of the directive to a property or attribute of the host element.

Example:

@HostBinding('style.color')
color = 'red';

7. Can directives receive inputs?

Answer

Yes.

Use the @Input() decorator to configure directive behavior from templates.


8. Can services be injected into directives?

Answer

Yes.

Angular Dependency Injection works in directives just as it does in components and services.


9. Are standalone directives supported?

Answer

Yes.

Angular supports standalone directives that can be imported directly into standalone components.


10. What are the best practices for custom directives?

Answer

  • Prefer Renderer2 over direct DOM manipulation.
  • Keep directives focused on UI behavior.
  • Avoid business logic.
  • Create reusable directives.
  • Use standalone directives in modern Angular.
  • Clean up subscriptions and event listeners.
  • Write unit tests for directive behavior.

Interview Cheat Sheet

Topic Remember
Decorator @Directive
DOM Access ElementRef
Preferred DOM API Renderer2
Events @HostListener
Host Properties @HostBinding
Inputs @Input()
Structural APIs TemplateRef, ViewContainerRef
Standalone Supported
Dependency Injection Supported
Best Practice Keep directives reusable

Summary

Custom Directives are a powerful Angular feature for encapsulating reusable UI behavior without creating new components. They allow developers to modify element appearance, respond to user interactions, and dynamically manipulate the DOM while promoting clean architecture and code reuse. By combining Renderer2, HostListener, HostBinding, Dependency Injection, and Standalone Directives, enterprise Angular applications can build maintainable, scalable, and reusable UI behavior with minimal duplication.


Key Takeaways

  • ✔ Custom Directives extend HTML behavior.
  • ✔ Attribute Directives modify existing elements.
  • ✔ Structural Directives create or remove views.
  • ✔ Prefer Renderer2 over direct DOM manipulation.
  • ✔ Use HostListener for event handling.
  • ✔ Use HostBinding for host element properties.
  • ✔ Support configurable behavior with @Input().
  • ✔ Standalone Directives simplify modern Angular development.
  • ✔ Keep directives lightweight and reusable.
  • ✔ Custom Directives are a common Angular interview topic.

Next Article

➡️ 30-Template-Reference-Variables-QA.md