How to create custom pipes in Angular
Creating custom pipes in Angular enables specialized data transformations that aren’t available with built-in pipes, providing reusable logic for specific business requirements and formatting needs. As the creator of CoreUI with extensive Angular experience since 2014, I’ve developed numerous custom pipes for enterprise applications requiring specialized formatting, filtering, and data transformation logic. The most effective approach involves implementing the PipeTransform interface with the @Pipe decorator to create reusable, performant transformation functions. This method provides clean separation of presentation logic while maintaining Angular’s change detection optimization and template readability.
Create custom pipes using the @Pipe decorator and PipeTransform interface for specialized data transformations in Angular applications.
import { Pipe, PipeTransform } from '@angular/core'
// Simple text transformation pipe
@Pipe({ name: 'truncate', pure: true })
export class TruncatePipe implements PipeTransform {
transform(value: string, limit: number = 50, suffix: string = '...'): string {
if (!value) return ''
if (value.length <= limit) return value
return value.substring(0, limit) + suffix
}
}
// Number formatting pipe
@Pipe({ name: 'fileSize', pure: true })
export class FileSizePipe implements PipeTransform {
transform(bytes: number, decimals: number = 2): string {
if (!bytes) return '0 Bytes'
const k = 1024
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i]
}
}
// Array filtering pipe
@Pipe({ name: 'search', pure: false })
export class SearchPipe implements PipeTransform {
transform(items: any[], searchTerm: string, keys: string[] = []): any[] {
if (!items || !searchTerm) return items
const term = searchTerm.toLowerCase()
return items.filter(item => {
if (keys.length > 0) {
return keys.some(key =>
item[key]?.toString().toLowerCase().includes(term)
)
}
return JSON.stringify(item).toLowerCase().includes(term)
})
}
}
// Date formatting pipe
@Pipe({ name: 'timeAgo', pure: true })
export class TimeAgoPipe implements PipeTransform {
transform(value: Date | string): string {
if (!value) return ''
const date = new Date(value)
const now = new Date()
const seconds = Math.floor((now.getTime() - date.getTime()) / 1000)
if (seconds < 60) return 'just now'
if (seconds < 3600) return `${Math.floor(seconds / 60)} minutes ago`
if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours ago`
if (seconds < 2592000) return `${Math.floor(seconds / 86400)} days ago`
return date.toLocaleDateString()
}
}
// Component using custom pipes
@Component({
selector: 'app-custom-pipes',
template: `
<div class="pipe-examples">
<h3>{{ longTitle | truncate:30 }}</h3>
<p>File size: {{ fileBytes | fileSize }}</p>
<p>Posted: {{ postDate | timeAgo }}</p>
<input [(ngModel)]="searchQuery" placeholder="Search users...">
<ul>
<li *ngFor="let user of users | search:searchQuery:['name', 'email']">
{{ user.name }} - {{ user.email }}
</li>
</ul>
</div>
`
})
export class CustomPipesComponent {
longTitle = 'This is a very long title that needs to be truncated for display purposes'
fileBytes = 1048576
postDate = new Date('2025-12-08')
searchQuery = ''
users = [
{ name: 'John Doe', email: '[email protected]' },
{ name: 'Jane Smith', email: '[email protected]' }
]
}
// Module registration
@NgModule({
declarations: [TruncatePipe, FileSizePipe, SearchPipe, TimeAgoPipe],
exports: [TruncatePipe, FileSizePipe, SearchPipe, TimeAgoPipe]
})
export class CustomPipesModule { }
This code demonstrates creating custom pipes with the @Pipe decorator and PipeTransform interface, implementing specialized transformation logic for text truncation, file size formatting, array searching, and relative time display. Pure pipes (pure: true) are optimized for performance and only re-evaluate when input changes, while impure pipes (pure: false) run on every change detection cycle. Custom pipes must be declared in NgModule to be available in templates and can accept multiple parameters for flexible transformation logic.
Best Practice Note:
This is the custom pipe architecture we use in CoreUI component libraries for reusable, performant data transformation across enterprise applications. Use pure pipes whenever possible for optimal performance and consider creating pipe libraries for common business logic to maintain consistency across projects.



