How Do You Create a Custom Directive in Angular?
A custom directive is a directive created by the developer to add reusable behavior or appearance to an existing HTML element or Angular component.
A common example is a custom attribute directive such as:
<p appHighlight>Hello Angular</p>
Here, appHighlight is our custom directive.
1. Why Do We Need Custom Directives?
Custom directives are useful when the same UI behavior needs to be reused in multiple places.
For example:
- Highlight an element.
- Change text color.
- Add hover effects.
- Automatically focus an input.
- Restrict certain user interactions.
- Apply reusable DOM behavior.
Instead of repeating the logic in multiple components, we put it inside a directive.
2. How to Create a Custom Directive
Using Angular CLI:
ng generate directive highlight
Short form:
ng g d highlight
This creates a directive file such as:
highlight.ts
With newer Angular CLI naming conventions, generated filenames may omit the .directive suffix.
3. Full Simple Sample Program
Let's create a custom directive that changes the text color when the mouse moves over an element.
highlight.ts
import {
Directive,
ElementRef,
HostListener,
Renderer2
} from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class Highlight {
constructor(
private element: ElementRef,
private renderer: Renderer2
) {
}
@HostListener('mouseenter')
onMouseEnter() {
this.renderer.setStyle(
this.element.nativeElement,
'color',
'red'
);
}
@HostListener('mouseleave')
onMouseLeave() {
this.renderer.removeStyle(
this.element.nativeElement,
'color'
);
}
}
app.ts
import { Component } from '@angular/core';
import { Highlight } from './highlight';
@Component({
selector: 'app-root',
standalone: true,
imports: [Highlight],
templateUrl: './app.html'
})
export class App {
}
app.html
<h1>Custom Directive Example</h1>
<p appHighlight>
Move the mouse over me
</p>
<h2 appHighlight>
Angular Custom Directive
</h2>
4. Explanation
Step 1: Create the Directive
@Directive({
selector: '[appHighlight]'
})
@Directive tells Angular:
This class represents an Angular directive.
The selector:
'[appHighlight]'
means the directive can be applied as an HTML attribute:
<p appHighlight>Hello</p>
Step 2: Access the Host Element
private element: ElementRef
ElementRef provides access to the element where the directive is applied.
For:
<p appHighlight>Hello</p>
the <p> is the host element.
Step 3: Use Renderer2
private renderer: Renderer2
Renderer2 provides Angular APIs for modifying the host element.
For example:
this.renderer.setStyle(
this.element.nativeElement,
'color',
'red'
);
This changes the text color to red.
Using Renderer2 is generally preferable to directly writing:
this.element.nativeElement.style.color = 'red';
because it keeps DOM manipulation behind Angular's rendering abstraction.
Step 4: Listen for Events
@HostListener('mouseenter')
@HostListener listens for events from the host element.
When the mouse enters:
onMouseEnter()
runs and changes the text to red.
When the mouse leaves:
@HostListener('mouseleave')
the directive removes the style.
5. Flow
<p appHighlight>
↓
Angular detects appHighlight
↓
Highlight directive is created
↓
ElementRef gets the <p>
↓
User moves mouse over <p>
↓
@HostListener detects mouseenter
↓
Renderer2 changes color
↓
Text becomes RED
When the mouse leaves:
mouseleave
↓
onMouseLeave()
↓
Renderer2 removes color
↓
Original style restored
6. Using the Directive in Standalone Angular
Because the directive is standalone in modern Angular, import it directly into the component that uses it:
imports: [Highlight]
Then use:
<p appHighlight>Hello</p>
This is the modern standalone approach.
Before Standalone Directives
Traditionally, the directive was declared inside an NgModule:
@NgModule({
declarations: [
AppComponent,
HighlightDirective
]
})
export class AppModule {
}
You would then use the directive in templates belonging to that module.
7. Custom Directive with Input
A directive can also accept values.
For example:
<p appHighlight="blue">
Hello Angular
</p>
Full Directive
import {
Directive,
ElementRef,
HostListener,
Input,
Renderer2
} from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class Highlight {
@Input() appHighlight = 'yellow';
constructor(
private element: ElementRef,
private renderer: Renderer2
) {
}
@HostListener('mouseenter')
onMouseEnter() {
this.renderer.setStyle(
this.element.nativeElement,
'background-color',
this.appHighlight
);
}
@HostListener('mouseleave')
onMouseLeave() {
this.renderer.removeStyle(
this.element.nativeElement,
'background-color'
);
}
}
Now:
<p appHighlight="yellow">Angular</p>
<p appHighlight="lightblue">ASP.NET Core</p>
The same directive can provide different behavior based on the input.
8. Advantages
- Provides reusable UI behavior.
- Reduces duplicate code.
- Keeps components cleaner.
- Can work with different HTML elements.
- Can respond to host events.
- Can accept configuration through inputs.
- Improves separation of concerns.
9. Disadvantages
- Too many custom directives can make templates difficult to understand.
- Complex business logic should not be placed inside directives.
- Direct DOM manipulation through
nativeElementshould be minimized. - A directive may be unnecessary when simple CSS or Angular binding can solve the requirement.
10. Key Points
- Custom directives are created using
@Directive. - Use Angular CLI:
ng g d highlight
- Attribute directives normally use an attribute selector:
selector: '[appHighlight]'
- Use it as:
<p appHighlight>Hello</p>
ElementRefprovides access to the host element.Renderer2can modify the host element.@HostListenerlistens to host events.- Inputs can make a directive configurable.
- In modern standalone Angular, import the directive directly into the component using it.
Interview Questions and Answers
Q1. How do you create a custom directive in Angular?
Create a directive using Angular CLI:
ng generate directive highlight
Then define its behavior using the @Directive decorator and import it wherever it is required.
Q2. Which decorator is used to create a directive?
The @Directive decorator:
@Directive({
selector: '[appHighlight]'
})
Q3. Why are square brackets used in the selector?
selector: '[appHighlight]'
They define appHighlight as an attribute selector, allowing it to be used as:
<p appHighlight>Hello</p>
Q4. What is ElementRef?
ElementRef provides access to the host DOM element on which the directive is applied.
Q5. What is Renderer2?
Renderer2 is Angular's rendering API for operations such as setting styles, attributes, classes, and properties on elements.
Q6. What is @HostListener?
@HostListener allows a directive to listen for events on its host element.
@HostListener('click')
onClick() {
}
Q7. Can we pass values to a custom directive?
Yes. A directive can accept values through inputs.
<p appHighlight="yellow">Hello</p>
Q8. How do you use a custom directive in a standalone component?
Import the directive:
@Component({
imports: [Highlight]
})
and then use its selector in the template:
<p appHighlight>Hello</p>
Q9. What is the best short interview answer?
A custom directive is created using the
@Directivedecorator. We define a selector, implement the required reusable behavior, import the directive into the standalone component, and apply its selector to an HTML element.