Comprehensive guide to custom templates and action columns with full Angular template syntax support
The ng-vui-grid component supports
custom column templates with full Angular template syntax. You can create action columns, custom
cell renderers, and header templates with complete control over the presentation and behavior.
Create rich, interactive grid experiences with action buttons, status badges, progress indicators, and complex UI components directly in your grid cells.
Full Angular template syntax with row data, column info, and row index
Buttons, dropdowns, and custom UI components with event handling
Custom column headers with sorting indicators and filters
Rich context with value, row data, column definition, and index
Define columns programmatically with custom renderers
Both declarative (template-based) and programmatic approaches
Define templates directly in your component template using Angular directive syntax.
<ng-vui-grid
[rowData]="data"
[gridOptions]="gridOptions"
>
<!-- Regular column with custom avatar template -->
<ng-template ngVuiGridColumn="name" headerName="Full Name" [width]="200">
<ng-template let-value let-row="row" let-rowIndex="rowIndex">
<div class="flex items-center space-x-3">
<div class="w-8 h-8 bg-violet-100 rounded-full flex items-center justify-center">
<span class="text-sm font-medium text-violet-600">
{{ row.name.charAt(0).toUpperCase() }}
</span>
</div>
<span class="font-medium text-gray-900">{{ value }}</span>
</div>
</ng-template>
</ng-template>
<!-- Action column with edit and delete buttons -->
<ng-template ngVuiGridColumn="actions" headerName="Actions" [width]="200" [sortable]="false">
<ng-template let-row="row" let-rowIndex="rowIndex">
<div class="flex items-center space-x-2">
<button
(click)="editRow(row, rowIndex)"
class="btn btn-sm btn-violet"
title="Edit"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>
</button>
<button
(click)="deleteRow(row, rowIndex)"
class="btn btn-sm btn-red"
title="Delete"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
</div>
</ng-template>
</ng-template>
<!-- Status column with colored badges -->
<ng-template ngVuiGridColumn="status" headerName="Status" [width]="120">
<ng-template let-value let-row="row">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
[class]="getStatusClass(value)"
>
{{ value }}
</span>
</ng-template>
</ng-template>
</ng-vui-grid>
Define columns programmatically in your TypeScript component for dynamic configurations.
export class MyComponent {
columnDefs: ColumnDefinition[] = [
{
field: 'name',
headerName: 'Full Name',
width: 200,
cellTemplate: this.nameTemplate // TemplateRef
},
{
field: 'email',
headerName: 'Email',
width: 250,
valueFormatter: ({ value }) => value.toLowerCase()
},
{
field: 'actions',
headerName: 'Actions',
width: 200,
sortable: false,
filterable: false,
cellTemplate: this.actionsTemplate // TemplateRef
}
];
// Get template references in component
@ViewChild('nameTemplate') nameTemplate!: TemplateRef<any>;
@ViewChild('actionsTemplate') actionsTemplate!: TemplateRef<any>;
}
Templates receive a rich context object with access to the cell value, row data, column definition, and row index for complete customization control.
interface TemplateContext {
$implicit: any; // The cell value (default template variable)
value: any; // The cell value (explicit access)
row: RowData; // The entire row data object
column: ColumnDefinition; // Column configuration
rowIndex: number; // Zero-based row index
}
let-value - Gets the cell value
let-row="row" - Gets the entire row
let-index="rowIndex" - Gets row index
let-col="column" - Gets column config
<ng-template ngVuiGridColumn="actions" headerName="Actions" [sortable]="false">
<ng-template let-row="row" let-rowIndex="rowIndex">
<div class="flex items-center space-x-2">
<button (click)="edit(row)" class="btn btn-sm btn-violet">Edit</button>
<button (click)="delete(row)" class="btn btn-sm btn-red">Delete</button>
</div>
</ng-template>
</ng-template>
<ng-template ngVuiGridColumn="actions" headerName="Actions" [sortable]="false">
<ng-template let-row="row" let-rowIndex="rowIndex">
<div class="relative">
<button (click)="toggleMenu(rowIndex)" class="btn btn-sm">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 5v.01M12 12v.01M12 19v.01"/>
</svg>
</button>
@if (openMenuIndex === rowIndex) {
<div class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg z-10">
<button (click)="edit(row)"
class="block w-full text-left px-4 py-2 hover:bg-gray-100">
Edit
</button>
<button (click)="duplicate(row)"
class="block w-full text-left px-4 py-2 hover:bg-gray-100">
Duplicate
</button>
<button (click)="delete(row)"
class="block w-full text-left px-4 py-2 hover:bg-gray-100 text-red-600">
Delete
</button>
</div>
}
</div>
</ng-template>
</ng-template>
<ng-template ngVuiGridColumn="actions" headerName="" [width]="120" [sortable]="false">
<ng-template let-row="row">
<div class="flex items-center justify-center space-x-1">
<button (click)="edit(row)"
class="p-2 hover:bg-gray-100 rounded"
title="Edit">
<svg class="w-4 h-4 text-violet-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>
</button>
<button (click)="view(row)"
class="p-2 hover:bg-gray-100 rounded"
title="View">
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
</svg>
</button>
<button (click)="delete(row)"
class="p-2 hover:bg-gray-100 rounded"
title="Delete">
<svg class="w-4 h-4 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
</div>
</ng-template>
</ng-template>
<ng-template ngVuiGridColumn="user" headerName="User" [width]="250">
<ng-template let-row="row">
<div class="flex items-center space-x-3">
<img
[src]="row.avatar || '/default-avatar.png'"
[alt]="row.name"
class="w-8 h-8 rounded-full"
/>
<div>
<div class="font-medium text-gray-900">{{ row.name }}</div>
<div class="text-sm text-gray-500">{{ row.email }}</div>
</div>
</div>
</ng-template>
</ng-template>
<ng-template ngVuiGridColumn="progress" headerName="Progress" [width]="150">
<ng-template let-value="value">
<div class="flex items-center space-x-2">
<div class="flex-1 bg-gray-200 rounded-full h-2">
<div
class="bg-violet-600 h-2 rounded-full transition-all duration-300"
[style.width.%]="value"
></div>
</div>
<span class="text-sm text-gray-600">{{ value }}%</span>
</div>
</ng-template>
</ng-template>
<ng-template ngVuiGridColumn="tags" headerName="Tags" [width]="200">
<ng-template let-value="value">
<div class="flex flex-wrap gap-1">
@for (tag of value; track tag) {
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-800">
{{ tag }}
</span>
}
</div>
</ng-template>
</ng-template>
<ng-template ngVuiGridColumn="status" headerName="Status" [width]="120">
<ng-template let-value="value">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
[ngClass]="{
'bg-green-100 text-green-800': value === 'Active',
'bg-red-100 text-red-800': value === 'Inactive',
'bg-yellow-100 text-yellow-800': value === 'Pending'
}"
>
{{ value }}
</span>
</ng-template>
</ng-template>
Implement these methods in your component to handle action column interactions:
export class MyComponent {
openMenuIndex: number | null = null;
editRow(row: RowData, index: number): void {
console.log('Edit:', row);
// Implement edit logic
// Example: Open edit dialog or navigate to edit page
}
deleteRow(row: RowData, index: number): void {
if (confirm('Are you sure you want to delete this item?')) {
this.rowData = this.rowData.filter(r => r.id !== row.id);
// Or call your delete service
this.dataService.delete(row.id).subscribe(() => {
this.loadData();
});
}
}
viewRow(row: RowData, index: number): void {
console.log('View:', row);
// Implement view logic
// Example: Open view dialog or navigate to detail page
}
duplicateRow(row: RowData, index: number): void {
const newRow = {
...row,
id: this.generateId(),
name: `${row.name} (Copy)`
};
this.rowData = [...this.rowData, newRow];
}
toggleMenu(index: number): void {
this.openMenuIndex = this.openMenuIndex === index ? null : index;
}
getStatusClass(status: string): string {
switch (status) {
case 'Active': return 'bg-green-100 text-green-800';
case 'Inactive': return 'bg-red-100 text-red-800';
case 'Pending': return 'bg-yellow-100 text-yellow-800';
default: return 'bg-gray-100 text-gray-800';
}
}
private generateId(): string {
return Math.random().toString(36).substr(2, 9);
}
}
Full Angular template syntax support with all directives and pipes
Strong typing with TypeScript interfaces and compile-time checks
Templates are compiled and cached for optimal performance
Full control over DOM structure and ARIA attributes
Easy integration with Tailwind CSS or any CSS framework
Templates can be shared across components and applications
The NgVuiGrid template syntax is designed to be intuitive and similar to other popular Angular grid libraries, making migration straightforward.
<!-- ngx-datatable example -->
<ngx-datatable>
<ngx-datatable-column name="actions">
<ng-template let-value="value" let-row="row" ngx-datatable-cell-template>
<!-- template content -->
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
<!-- NgVuiGrid equivalent -->
<ng-vui-grid>
<ng-template ngVuiGridColumn="actions">
<ng-template let-value="value" let-row="row">
<!-- template content -->
</ng-template>
</ng-template>
</ng-vui-grid>
ngVuiGridColumn
ColumnDefinition
GridOptions interface