npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ng-vui/ng-vui-grid

v1.0.2

Published

Advanced Angular Data Grid Component with Templates, Sorting, Filtering, and Export features

Downloads

312

Readme

@ng-vui/ng-vui-grid

A powerful, feature-rich Angular 20+ data grid component with advanced template support, action columns, sorting, filtering, pagination, virtual scrolling, and export capabilities. Built with standalone components and modern Angular architecture.

🚀 Features

  • Standalone Components - Modern Angular 20+ standalone architecture
  • Custom Cell Templates - Full Angular template syntax support
  • Action Columns - Buttons, dropdowns, and interactive elements
  • Advanced Sorting - Multi-column sorting with custom comparators
  • Flexible Filtering - Built-in and custom filter types
  • Server-Side Operations - Server-side pagination, filtering, and sorting
  • Data Streaming - Real-time data streaming support
  • Virtual Scrolling - Handle large datasets efficiently (100k+ rows)
  • Security Features - Input validation and XSS protection
  • Data Export - CSV, Excel, and PDF export
  • Column Management - Show/hide, resize, reorder columns
  • Row Selection - Single and multi-select with checkboxes
  • Responsive Design - Mobile-friendly with Tailwind CSS
  • TypeScript Support - Full type safety and IntelliSense
  • State Management - Grid state persistence and restoration

📦 Installation

npm install @ng-vui/ng-vui-grid

Peer Dependencies:

  • Angular 17+ (@angular/core, @angular/common, @angular/forms)
  • RxJS 6.5+ or 7+

🏗️ Architecture

Built with modern Angular patterns:

  • Standalone Components - No NgModules required
  • Signal-based State - Reactive state management
  • Feature Modules - Modular filtering, editing, export capabilities
  • Service Architecture - Dedicated services for different concerns
  • Type Safety - Full TypeScript interfaces and types

🎯 Basic Usage

Template-Based Approach (Recommended)

import {
  NgVuiGridComponent,
  NgVuiGridColumnDirective,
  GridOptions,
  DEFAULT_GRID_OPTIONS
} from '@ng-vui/ng-vui-grid';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [NgVuiGridComponent, NgVuiGridColumnDirective],
  template: `
    <ng-vui-grid
      [rowData]="data"
      [gridOptions]="gridOptions"
      (gridReady)="onGridReady($event)"
    >
      <!-- Regular column -->
      <ng-template ngVuiGridColumn="name" headerName="Full Name" [width]="200" let-value>
        <span class="font-medium">{{ value }}</span>
      </ng-template>

      <!-- Action column -->
      <ng-template ngVuiGridColumn="actions" headerName="Actions" [width]="150" [sortable]="false" let-row="row">
        <button (click)="edit(row)" class="btn btn-sm btn-primary mr-2">Edit</button>
        <button (click)="delete(row)" class="btn btn-sm btn-danger">Delete</button>
      </ng-template>
    </ng-vui-grid>
  `
})
export class ExampleComponent {
  data = [
    { id: 1, name: 'John Doe', email: '[email protected]', status: 'Active' },
    { id: 2, name: 'Jane Smith', email: '[email protected]', status: 'Inactive' }
  ];

  gridOptions: GridOptions = {
    ...DEFAULT_GRID_OPTIONS,
    pagination: true,
    paginationPageSize: 20,
    enableSorting: true,
    enableFiltering: true,
    enableSelection: true,
    header: {
      showTitle: true,
      title: 'User Management',
      showControls: true,
      showColumnChooser: true,
      showExport: true
    }
  };

  onGridReady(event: GridReadyEvent) {
    console.log('Grid is ready:', event);
  }

  edit(row: any) {
    console.log('Edit:', row);
  }

  delete(row: any) {
    console.log('Delete:', row);
  }
}

Programmatic Approach

import { NgGridComponent, ColumnDefinition } from '@ertpl-ui/ang-grid';

@Component({
  template: `
    <ng-grid 
      [columnDefs]="columns" 
      [rowData]="data" 
      [gridOptions]="gridOptions"
    ></ng-grid>
  `
})
export class ProgrammaticExample {
  columns: ColumnDefinition[] = [
    { field: 'name', headerName: 'Full Name', width: 200, sortable: true },
    { field: 'email', headerName: 'Email', width: 250, filterable: true },
    { field: 'status', headerName: 'Status', width: 120 }
  ];

  data = [...]; // Your data array
  gridOptions = {...}; // Your grid options
}

🎨 Template Context

Templates receive the following context variables:

interface TemplateContext {
  $implicit: any;        // The cell value
  value: any;            // The cell value (same as $implicit)
  row: RowData;          // The entire row data
  column: ColumnDefinition; // Column definition
  rowIndex: number;      // Row index
}

Usage in Templates

<ng-template ngGridColumn="user" headerName="User Info" let-value let-row="row" let-rowIndex="rowIndex">
  <div class="flex items-center">
    <img [src]="row.avatar" class="w-8 h-8 rounded-full mr-3">
    <div>
      <div class="font-medium">{{ value }}</div>
      <div class="text-sm text-gray-500">Row #{{ rowIndex + 1 }}</div>
    </div>
  </div>
</ng-template>

🔧 API Reference

NgGridComponent

Inputs

| Property | Type | Default | Description | |----------|------|---------|-------------| | rowData | RowData[] | [] | Array of data objects | | columnDefs | ColumnDefinition[] | [] | Column definitions (programmatic) | | gridOptions | GridOptions | {} | Grid configuration options | | loading | boolean | false | Show loading indicator | | loadingTemplate | TemplateRef | - | Custom loading template | | noDataTemplate | TemplateRef | - | Custom no data template |

Outputs

| Event | Type | Description | |-------|------|-------------| | gridReady | GridReadyEvent | Fired when grid is initialized | | cellClicked | CellClickedEvent | Fired when cell is clicked | | rowSelected | RowSelectedEvent | Fired when row selection changes | | sortChanged | SortEvent[] | Fired when sorting changes | | filterChanged | FilterEvent | Fired when filtering changes |

ColumnDefinition

interface ColumnDefinition {
  field: string;                    // Data field name
  headerName?: string;              // Column header text
  width?: number;                   // Fixed width in pixels
  minWidth?: number;                // Minimum width
  maxWidth?: number;                // Maximum width
  sortable?: boolean;               // Enable sorting
  filterable?: boolean;             // Enable filtering
  resizable?: boolean;              // Allow column resizing
  visible?: boolean;                // Show/hide column
  pinned?: 'left' | 'right';       // Pin column to left/right
  cellTemplate?: TemplateRef<any>;  // Custom cell template
  headerTemplate?: TemplateRef<any>; // Custom header template
  valueFormatter?: (params: any) => string; // Format cell value
  cellClass?: string | string[];    // CSS classes for cell
  headerClass?: string | string[];  // CSS classes for header
}

GridOptions

interface GridOptions {
  // Pagination
  pagination?: boolean;             // Enable pagination
  paginationPageSize?: number;      // Rows per page
  paginationPageSizes?: number[];   // Available page sizes

  // Sorting & Filtering
  enableSorting?: boolean;          // Enable sorting
  enableFiltering?: boolean;        // Enable filtering
  multiSort?: boolean;              // Allow multi-column sorting

  // Selection
  enableSelection?: boolean;        // Enable row selection
  selectionMode?: 'single' | 'multiple'; // Selection mode
  showSelectionCheckbox?: boolean;  // Show selection checkboxes

  // Virtual Scrolling
  virtualScrolling?: boolean;       // Enable virtual scrolling
  rowHeight?: number;               // Fixed row height

  // Header Options
  header?: {
    showTitle?: boolean;            // Show grid title
    title?: string;                 // Grid title text
    showControls?: boolean;         // Show header controls
    exportControls?: {              // Export options
      enabled?: boolean;
      showCsv?: boolean;
      showExcel?: boolean;
      showPdf?: boolean;
    };
    columnControls?: {              // Column options
      enabled?: boolean;
      showColumnSelector?: boolean;
    };
  };

  // Styling
  cssClasses?: {
    root?: string;                  // Grid container classes
    header?: string;                // Header classes
    body?: string;                  // Body classes
    row?: string;                   // Row classes
    cell?: string;                  // Cell classes
  };
}

🎯 Advanced Examples

Action Column with Dropdown

<ng-template ngGridColumn="actions" headerName="Actions" [sortable]="false" 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>

Status Badge Column

<ng-template ngGridColumn="status" headerName="Status" let-value>
  <span [class]="getStatusClass(value)" class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium">
    {{ value }}
  </span>
</ng-template>
getStatusClass(status: string): string {
  const classes = {
    'Active': 'bg-green-100 text-green-800',
    'Pending': 'bg-yellow-100 text-yellow-800',
    'Inactive': 'bg-red-100 text-red-800'
  };
  return classes[status] || 'bg-gray-100 text-gray-800';
}

Progress Bar Column

<ng-template ngGridColumn="progress" headerName="Progress" let-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" [style.width.%]="value"></div>
    </div>
    <span class="text-sm text-gray-600">{{ value }}%</span>
  </div>
</ng-template>

Image with Text Column

<ng-template ngGridColumn="user" headerName="User" let-row="row">
  <div class="flex items-center space-x-3">
    <img [src]="row.avatar || '/default-avatar.png'" [alt]="row.name" class="w-10 h-10 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>

📤 Data Export

// Component method
export() {
  this.gridApi?.exportDataAsCsv({
    fileName: 'data-export.csv',
    columnKeys: ['name', 'email', 'status'],
    skipHeaders: false
  });
}

// Excel export
exportExcel() {
  this.gridApi?.exportDataAsExcel({
    fileName: 'data-export.xlsx',
    sheetName: 'Data'
  });
}

// PDF export
exportPdf() {
  this.gridApi?.exportDataAsPdf({
    fileName: 'data-export.pdf',
    title: 'Data Report'
  });
}

🎨 Styling & Theming

Default Tailwind Classes

The component uses Tailwind CSS by default. You can customize the appearance:

gridOptions: GridOptions = {
  cssClasses: {
    root: 'rounded-lg border border-gray-200',
    header: 'bg-gray-50 border-b',
    body: 'bg-white',
    row: 'hover:bg-gray-50 border-b border-gray-100',
    cell: 'px-4 py-3'
  }
};

Custom CSS

/* Custom grid styling */
.my-grid {
  --grid-border-color: #e5e7eb;
  --grid-header-bg: #f9fafb;
  --grid-row-hover: #f3f4f6;
}

.my-grid .grid-header {
  background: var(--grid-header-bg);
}

.my-grid .grid-row:hover {
  background: var(--grid-row-hover);
}

🔌 Integration Examples

With Angular Reactive Forms

@Component({
  template: `
    <ng-grid [rowData]="formData" [gridOptions]="options">
      <ng-template ngGridColumn="isActive" headerName="Active" let-value let-row="row">
        <input type="checkbox" [checked]="value" (change)="updateField(row, 'isActive', $event.target.checked)">
      </ng-template>
    </ng-grid>
  `
})
export class FormGridExample {
  updateField(row: any, field: string, value: any) {
    const index = this.formData.indexOf(row);
    this.formData[index][field] = value;
    // Update your reactive form here
  }
}

With HTTP Service

@Component({
  template: `
    <ng-grid 
      [rowData]="data$ | async" 
      [loading]="loading"
      [gridOptions]="options"
      (sortChanged)="onSort($event)"
      (filterChanged)="onFilter($event)"
    ></ng-grid>
  `
})
export class ServerDataExample {
  data$ = this.dataService.getData();
  loading = false;

  onSort(sorts: SortEvent[]) {
    this.loading = true;
    this.data$ = this.dataService.getData({ sort: sorts }).pipe(
      finalize(() => this.loading = false)
    );
  }

  onFilter(filter: FilterEvent) {
    this.loading = true;
    this.data$ = this.dataService.getData({ filter }).pipe(
      finalize(() => this.loading = false)
    );
  }
}

🧪 Testing

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NgGridComponent } from '@ertpl-ui/ang-grid';

describe('NgGridComponent', () => {
  let component: NgGridComponent;
  let fixture: ComponentFixture<NgGridComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [NgGridComponent]
    });
    fixture = TestBed.createComponent(NgGridComponent);
    component = fixture.componentInstance;
  });

  it('should render data correctly', () => {
    component.rowData = [{ id: 1, name: 'Test' }];
    fixture.detectChanges();
    
    expect(fixture.nativeElement.textContent).toContain('Test');
  });
});

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Commit changes: git commit -am 'Add my feature'
  4. Push to branch: git push origin feature/my-feature
  5. Submit a pull request

🚨 Recent Updates & Fixes

Angular 20+ Compatibility ✅

  • Fixed ng build issues with ng-packagr
  • Resolved cross-library import dependencies
  • Updated peer dependencies to support Angular 17-20+
  • Improved TypeScript compilation with strict mode

Build & Architecture Improvements ✅

  • Standalone Components: Full migration to modern Angular architecture
  • Signal-based State: Reactive state management implementation
  • Fixed Import Issues: Resolved relative import problems causing build failures
  • Enhanced Type Safety: Complete TypeScript interface coverage

Performance & Security ✅

  • Virtual Scrolling: Handle 10M+ records efficiently
  • XSS Protection: Enhanced security with input validation
  • Memory Optimization: Improved garbage collection and state management
  • Bundle Size: Reduced bundle size with standalone components

📄 License

MIT © VUI

📚 Comprehensive Documentation

For detailed information about specific features, see these comprehensive guides:

Core Documentation

Performance & Optimization

Security & Best Practices

🔗 Related Packages

  • @ng-vui/multi-select - Multi-select dropdown component
  • @ng-vui/date-picker - Date picker component
  • @ng-vui/select-input - Single select dropdown
  • @ng-vui/text-input - Text input component
  • @ng-vui/textarea - Textarea component
  • @ng-vui/auto-complete - Auto complete component