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

ngx-simple-datatable

v0.6.3

Published

Modern Angular DataTable component with Signals support

Readme

ngx-simple-datatable

npm Version Build Status GitHub Stars Angular TypeScript MIT License

A modern Angular DataTable component with Signal-based reactivity and intelligent column sizing

Live ExamplesDocumentationReport Bug

✨ Features

  • 🎯 Angular Native - Built specifically for Angular 17-20
  • 🎭 Standalone Components - No NgModule required
  • 🚀 Signal-Based Reactivity - Optimized performance with Angular signals
  • 🎨 Modern Control Flow - Uses @if, @for, @switch syntax for better performance
  • 📊 Advanced Data Operations - Sorting, filtering, pagination, and search
  • 🔍 Column Filtering - Individual column filters with multiple conditions
  • 📱 Responsive Design - Mobile-first approach with touch optimization
  • 🎪 Custom Templates - Slot-based system for complete customization
  • 🎨 Comprehensive Theming - CSS custom properties with dark mode support
  • Performance Optimized - Virtual scrolling and efficient rendering
  • 📈 Server-Side Support - Full server-side operations compatibility
  • Accessibility First - WCAG compliant with screen reader support
  • 🔧 TypeScript - Full type safety and IntelliSense
  • 🌍 i18n Ready - Internationalization support
  • 📏 Intelligent Column Sizing - Multiple sizing strategies with responsive calculation
  • 🔄 Flexible Layout Control - Auto-fit, auto-width, and hybrid sizing modes
  • 📐 Minimum Width Respect - Preserve readability with configurable constraints
  • ↔️ Horizontal Scroll Support - Optional horizontal scrolling for wide tables
  • 🎛️ Column Priority System - Control which columns shrink first

🚀 Quick Start

Installation

npm install ngx-simple-datatable
# or
yarn add ngx-simple-datatable
# or
pnpm add ngx-simple-datatable

CSS Import

Add the CSS to your angular.json:

{
  "styles": ["node_modules/ngx-simple-datatable/ngx-simple-datatable.css"]
}

Or import in your global styles.css:

@import 'ngx-simple-datatable/ngx-simple-datatable.css';

Basic Usage

import { Component, signal } from '@angular/core';
import { SimpleDatatableComponent } from 'ngx-simple-datatable';
import { Column } from 'ngx-simple-datatable';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [SimpleDatatableComponent],
  template: `
    <ngx-simple-datatable
      [rows]="rows()"
      [columns]="columns()"
      [loading]="loading()"
      [hasCheckbox]="true"
      [pagination]="true"
      [sortable]="true"
      [columnFilter]="true"
      [columnSizingStrategy]="'hybrid'"
      [preserveReadability]="true"
      (rowSelect)="onRowSelect($event)"
      (sortChange)="onSortChange($event)"
    >
    </ngx-simple-datatable>
  `,
})
export class ExampleComponent {
  loading = signal(false);

  columns = signal<Column[]>([
    {
      field: 'id',
      title: 'ID',
      type: 'number',
      width: '80px',
      strict: true, // This column won't shrink
    },
    {
      field: 'name',
      title: 'Name',
      type: 'string',
      minWidth: '120px',
      preferredWidth: '200px',
    },
    {
      field: 'email',
      title: 'Email',
      type: 'string',
      shrinkPriority: 2, // Lower priority = shrinks first
    },
    {
      field: 'active',
      title: 'Active',
      type: 'bool',
      strict: true,
    },
    {
      field: 'createdAt',
      title: 'Created',
      type: 'date',
      shrinkPriority: 1,
    },
  ]);

  rows = signal([
    {
      id: 1,
      name: 'John Doe',
      email: '[email protected]',
      active: true,
      createdAt: new Date(),
    },
    // ... more data
  ]);

  onRowSelect(selectedRows: any[]) {
    console.log('Selected rows:', selectedRows);
  }

  onSortChange(event: { field: string; direction: 'asc' | 'desc' }) {
    console.log('Sort changed:', event);
  }
}

📋 Advanced Examples

Column Sizing Strategies

// Auto-fit: Columns expand to fill container (default)
@Component({
  template: `
    <ngx-simple-datatable
      [rows]="data()"
      [columns]="columns()"
      columnSizingStrategy="auto-fit"
      [expandToFillContainer]="true"
    >
    </ngx-simple-datatable>
  `,
})
export class AutoFitExample {}

// Auto-width: Respect minimum widths, allow horizontal scroll
@Component({
  template: `
    <ngx-simple-datatable
      [rows]="data()"
      [columns]="columns()"
      columnSizingStrategy="auto-width"
      [allowHorizontalScroll]="true"
      [preserveReadability]="true"
    >
    </ngx-simple-datatable>
  `,
})
export class AutoWidthExample {}

// Hybrid: Expand if space available, respect minimums
@Component({
  template: `
    <ngx-simple-datatable
      [rows]="data()"
      [columns]="columns()"
      columnSizingStrategy="hybrid"
      [respectColumnMinWidths]="true"
      minTableWidth="800px"
    >
    </ngx-simple-datatable>
  `,
})
export class HybridExample {}

Advanced Column Configuration

@Component({
  selector: 'app-advanced-columns',
  template: `
    <ngx-simple-datatable
      [rows]="users()"
      [columns]="advancedColumns()"
      [columnSizingStrategy]="'hybrid'"
      [preserveReadability]="true"
      [allowHorizontalScroll]="true"
    >
    </ngx-simple-datatable>
  `,
})
export class AdvancedColumnsComponent {
  advancedColumns = signal<Column[]>([
    {
      field: 'id',
      title: 'ID',
      type: 'number',
      width: '60px',
      strict: true, // Never shrink this column
      sort: true,
      filter: false,
    },
    {
      field: 'avatar',
      title: '',
      width: '50px',
      strict: true,
      sort: false,
      filter: false,
    },
    {
      field: 'name',
      title: 'Full Name',
      type: 'string',
      preferredWidth: '200px',
      minWidth: '120px',
      maxWidth: '300px',
      shrinkPriority: 3, // Lower priority = shrinks later
    },
    {
      field: 'email',
      title: 'Email Address',
      type: 'string',
      preferredWidth: '250px',
      minWidth: '150px',
      shrinkPriority: 1, // Higher priority = shrinks first
    },
    {
      field: 'department',
      title: 'Department',
      type: 'string',
      preferredWidth: '150px',
      minWidth: '100px',
      shrinkPriority: 2,
    },
    {
      field: 'salary',
      title: 'Salary',
      type: 'number',
      preferredWidth: '120px',
      minWidth: '100px',
      strict: false,
      cellRenderer: row => `$${row.salary.toLocaleString()}`,
    },
    {
      field: 'actions',
      title: 'Actions',
      width: '120px',
      strict: true,
      sort: false,
      filter: false,
    },
  ]);
}

Responsive Tables

@Component({
  selector: 'app-responsive-table',
  template: `
    <!-- Desktop: Auto-fit with full expansion -->
    <div class="d-none d-lg-block">
      <ngx-simple-datatable
        [rows]="data()"
        [columns]="columns()"
        columnSizingStrategy="auto-fit"
        [expandToFillContainer]="true"
      >
      </ngx-simple-datatable>
    </div>

    <!-- Tablet: Hybrid approach -->
    <div class="d-none d-md-block d-lg-none">
      <ngx-simple-datatable
        [rows]="data()"
        [columns]="columns()"
        columnSizingStrategy="hybrid"
        [respectColumnMinWidths]="true"
        [allowHorizontalScroll]="true"
      >
      </ngx-simple-datatable>
    </div>

    <!-- Mobile: Preserve readability with scroll -->
    <div class="d-md-none">
      <ngx-simple-datatable
        [rows]="data()"
        [columns]="mobileColumns()"
        columnSizingStrategy="auto-width"
        [preserveReadability]="true"
        [allowHorizontalScroll]="true"
        class="ngx-sdt-mobile-stack"
      >
      </ngx-simple-datatable>
    </div>
  `,
})
export class ResponsiveTableComponent {
  // Reduced columns for mobile
  mobileColumns = computed(() => this.columns().filter(col => ['name', 'email', 'actions'].includes(col.field)));
}

Modern Angular 17+ Features

import { Component, signal, computed } from '@angular/core';
import { SimpleDatatableComponent, SlotDirective } from 'ngx-simple-datatable';

@Component({
  selector: 'app-advanced-example',
  standalone: true,
  imports: [SimpleDatatableComponent, SlotDirective],
  template: `
    <ngx-simple-datatable
      [rows]="filteredUsers()"
      [columns]="columns()"
      [loading]="isLoading()"
      [stickyHeader]="true"
      [stickyFirstColumn]="true"
      [height]="'600px'"
      [columnSizingStrategy]="'hybrid'"
      [preserveReadability]="true"
      skin="ngx-sdt-table--striped ngx-sdt-table--hover"
      tableClass="modern-table"
      (rowClick)="onRowClick($event)"
      (filterChange)="onFilterChange($event)"
    >
      <!-- Custom Status Column -->
      <ng-template ngxSimpleDatatableSlot="status" let-data="data">
        @if (data.status === 'active') {
          <span class="badge bg-success">Active</span>
        } @else if (data.status === 'pending') {
          <span class="badge bg-warning">Pending</span>
        } @else {
          <span class="badge bg-danger">Inactive</span>
        }
      </ng-template>

      <!-- Custom Actions Column -->
      <ng-template ngxSimpleDatatableSlot="actions" let-data="data">
        <div class="btn-group">
          <button class="btn btn-sm btn-primary" (click)="editUser(data)">Edit</button>
          <button class="btn btn-sm btn-danger" (click)="deleteUser(data)">Delete</button>
        </div>
      </ng-template>

      <!-- Custom Avatar Column -->
      <ng-template ngxSimpleDatatableSlot="avatar" let-data="data">
        <img
          [src]="data.avatar || 'assets/default-avatar.png'"
          [alt]="data.name"
          class="rounded-circle"
          width="40"
          height="40"
        />
      </ng-template>
    </ngx-simple-datatable>
  `,
})
export class AdvancedExampleComponent {
  isLoading = signal(false);
  searchTerm = signal('');

  users = signal([
    {
      id: 1,
      name: 'Alice Johnson',
      email: '[email protected]',
      status: 'active',
      role: 'Admin',
      avatar: 'https://i.pravatar.cc/150?img=1',
      salary: 75000,
      joinDate: new Date('2023-01-15'),
    },
    // ... more users
  ]);

  columns = signal<Column[]>([
    {
      field: 'avatar',
      title: '',
      width: '60px',
      sort: false,
      filter: false,
      strict: true,
    },
    {
      field: 'id',
      title: 'ID',
      type: 'number',
      width: '80px',
      isUnique: true,
      strict: true,
    },
    {
      field: 'name',
      title: 'Full Name',
      type: 'string',
      cellClass: 'fw-bold',
      preferredWidth: '200px',
      minWidth: '120px',
      shrinkPriority: 4,
    },
    {
      field: 'email',
      title: 'Email Address',
      type: 'string',
      preferredWidth: '250px',
      minWidth: '150px',
      shrinkPriority: 1,
    },
    {
      field: 'status',
      title: 'Status',
      type: 'string',
      width: '120px',
      strict: true,
    },
    {
      field: 'salary',
      title: 'Salary',
      type: 'number',
      cellRenderer: row => `$${row.salary.toLocaleString()}`,
      preferredWidth: '120px',
      minWidth: '100px',
      shrinkPriority: 3,
    },
    {
      field: 'joinDate',
      title: 'Join Date',
      type: 'date',
      preferredWidth: '140px',
      minWidth: '120px',
      shrinkPriority: 2,
    },
    {
      field: 'actions',
      title: 'Actions',
      width: '150px',
      sort: false,
      filter: false,
      strict: true,
    },
  ]);

  // Computed property using signals
  filteredUsers = computed(() => {
    const term = this.searchTerm().toLowerCase();
    if (!term) return this.users();

    return this.users().filter(
      user => user.name.toLowerCase().includes(term) || user.email.toLowerCase().includes(term)
    );
  });

  onRowClick(event: { item: any; index: number }) {
    console.log('Row clicked:', event);
  }

  onFilterChange(columns: Column[]) {
    console.log('Filters changed:', columns);
  }

  editUser(user: any) {
    console.log('Edit user:', user);
  }

  deleteUser(user: any) {
    console.log('Delete user:', user);
  }
}

Server-Side Operations

@Component({
  template: `
    <ngx-simple-datatable
      [rows]="serverData()"
      [columns]="columns()"
      [isServerMode]="true"
      [totalRows]="totalRows()"
      [loading]="loading()"
      [page]="currentPage()"
      [pageSize]="pageSize()"
      [sortColumn]="sortColumn()"
      [sortDirection]="sortDirection()"
      [search]="searchTerm()"
      [columnSizingStrategy]="'hybrid'"
      [respectColumnMinWidths]="true"
      (changeServer)="onServerChange($event)"
    >
    </ngx-simple-datatable>
  `,
})
export class ServerSideComponent {
  serverData = signal<any[]>([]);
  totalRows = signal(0);
  loading = signal(false);
  currentPage = signal(1);
  pageSize = signal(10);
  sortColumn = signal('id');
  sortDirection = signal<'asc' | 'desc'>('asc');
  searchTerm = signal('');

  columns = signal<Column[]>([
    { field: 'id', title: 'ID', type: 'number', strict: true },
    { field: 'name', title: 'Name', type: 'string', minWidth: '120px' },
    { field: 'email', title: 'Email', type: 'string', minWidth: '150px' },
    { field: 'status', title: 'Status', type: 'string' },
  ]);

  constructor(private dataService: DataService) {
    this.loadData();
  }

  onServerChange(state: DatatableState) {
    this.loading.set(true);

    // Update current state
    this.currentPage.set(state.currentPage);
    this.pageSize.set(state.pageSize);
    this.sortColumn.set(state.sortColumn);
    this.sortDirection.set(state.sortDirection);
    this.searchTerm.set(state.search);

    // Load data from server
    this.dataService.getData(state).subscribe({
      next: response => {
        this.serverData.set(response.data);
        this.totalRows.set(response.total);
        this.loading.set(false);
      },
      error: () => {
        this.loading.set(false);
      },
    });
  }

  private loadData() {
    this.onServerChange({
      currentPage: this.currentPage(),
      pageSize: this.pageSize(),
      offset: 0,
      sortColumn: this.sortColumn(),
      sortDirection: this.sortDirection(),
      search: this.searchTerm(),
      columnFilters: this.columns(),
      changeType: 'page',
    });
  }
}

Custom Theming

@Component({
  selector: 'app-themed-table',
  template: `
    <!-- Dark theme -->
    <ngx-simple-datatable class="dark-mode custom-theme" [rows]="data()" [columns]="columns()"> </ngx-simple-datatable>

    <!-- Custom corporate theme -->
    <ngx-simple-datatable class="corporate-theme" [rows]="data()" [columns]="columns()"> </ngx-simple-datatable>

    <!-- Bootstrap integration -->
    <ngx-simple-datatable class="bs-compat" [rows]="data()" [columns]="columns()"> </ngx-simple-datatable>
  `,
  styles: [
    `
      .custom-theme {
        --ngx-sdt-color-primary: #8b5cf6;
        --ngx-sdt-color-primary-hover: #7c3aed;
        --ngx-sdt-color-primary-light: #ede9fe;
        --ngx-sdt-border-radius-lg: 1rem;
        --ngx-sdt-shadow-md: 0 8px 32px rgba(139, 92, 246, 0.15);
      }

      .corporate-theme {
        --ngx-sdt-color-primary: #0f4c75;
        --ngx-sdt-color-secondary: #5a6c7d;
        --ngx-sdt-border-radius-md: 0.25rem;
        --ngx-sdt-font-weight-medium: 600;
      }
    `,
  ],
})
export class ThemedTableComponent {
  // ... component logic
}

🔧 API Reference

Component Properties

| Property | Type | Default | Description | | ------------------------ | ----------------------------------- | -------------------------- | ----------------------------------------- | | rows | any[] | [] | Table data rows | | columns | Column[] | [] | Table column definitions | | loading | boolean | false | Show loading state | | isServerMode | boolean | false | Enable server-side operations | | totalRows | number | 0 | Total rows for server-side pagination | | hasCheckbox | boolean | false | Enable row selection checkboxes | | selectRowOnClick | boolean | false | Select row on click | | search | string | '' | Global search term | | page | number | 1 | Current page number | | pageSize | number | 10 | Rows per page | | pageSizeOptions | number[] | [10, 20, 30, 50, 100] | Page size options | | showPageSize | boolean | true | Show page size selector | | sortable | boolean | true | Enable column sorting | | sortColumn | string | 'id' | Default sort column | | sortDirection | 'asc' \| 'desc' | 'asc' | Default sort direction | | columnFilter | boolean | false | Enable column filtering | | pagination | boolean | true | Enable pagination | | showNumbers | boolean | true | Show page numbers | | showNumbersCount | number | 5 | Number of page buttons to show | | showFirstPage | boolean | true | Show first page button | | showLastPage | boolean | true | Show last page button | | firstArrow | string | '' | Custom first page arrow HTML | | lastArrow | string | '' | Custom last page arrow HTML | | nextArrow | string | '' | Custom next page arrow HTML | | previousArrow | string | '' | Custom previous page arrow HTML | | paginationInfo | string | 'Showing {0} to {1}...' | Pagination info template | | noDataContent | string | 'No data available' | No data message | | stickyHeader | boolean | false | Fixed header | | height | string | '500px' | Table height (when sticky header enabled) | | stickyFirstColumn | boolean | false | Fixed first column | | cloneHeaderInFooter | boolean | false | Clone header in footer | | skin | string | 'ngx-sdt-table--striped' | Table styling classes | | tableClass | string | '' | Custom table CSS class | | rowClass | string \| ((item: any) => string) | '' | Custom row CSS class | | cellClass | string \| ((item: any) => string) | '' | Custom cell CSS class | | autoCalculateWidths | boolean | true | Auto-calculate column widths | | expandToFillContainer | boolean | true | Expand table to fill container | | columnSizingStrategy | ColumnSizingStrategy | 'auto-fit' | Column sizing strategy | | respectColumnMinWidths | boolean | false | Respect minimum column widths | | allowHorizontalScroll | boolean | true | Allow horizontal scroll when needed | | minTableWidth | string | '' | Minimum table width | | preserveReadability | boolean | true | Preserve text readability over fitting |

Column Interface

interface Column {
  field: string; // Data field name
  title?: string; // Display title
  type?: 'string' | 'number' | 'date' | 'bool'; // Column data type
  width?: string; // Fixed width
  minWidth?: string; // Minimum width
  maxWidth?: string; // Maximum width
  preferredWidth?: string; // Preferred width for hybrid mode
  strict?: boolean; // Never allow this column to shrink
  shrinkPriority?: number; // Priority for shrinking (1 = shrinks first)
  isUnique?: boolean; // Primary key field
  hide?: boolean; // Hide column
  filter?: boolean; // Enable filtering
  search?: boolean; // Include in global search
  sort?: boolean; // Enable sorting
  value?: any; // Filter value
  condition?: FilterCondition; // Filter condition
  cellRenderer?: ((item: any) => string) | string; // Custom cell renderer
  headerClass?: string; // Header CSS class
  cellClass?: string; // Cell CSS class
  html?: boolean; // Allow HTML content
}

Column Sizing Strategies

type ColumnSizingStrategy = 'auto-fit' | 'auto-width' | 'hybrid';

// auto-fit: Columns expand to fill available container width
// auto-width: Respect minimum widths, allow horizontal scroll
// hybrid: Expand if space available, respect minimums otherwise

Filter Conditions

type FilterCondition =
  | ''
  | 'contain'
  | 'not_contain'
  | 'equal'
  | 'not_equal'
  | 'start_with'
  | 'end_with'
  | 'greater_than'
  | 'greater_than_equal'
  | 'less_than'
  | 'less_than_equal'
  | 'is_null'
  | 'is_not_null';

Events

| Event | Type | Description | | ---------------- | ------------------------------------------ | -------------------------- | | changeServer | EventEmitter<DatatableState> | Server-side state changes | | sortChange | EventEmitter<{field: string, direction}> | Sort change event | | searchChange | EventEmitter<string> | Search change event | | pageChange | EventEmitter<number> | Page change event | | pageSizeChange | EventEmitter<number> | Page size change event | | rowSelect | EventEmitter<any[]> | Row selection change event | | filterChange | EventEmitter<Column[]> | Filter change event | | rowClick | EventEmitter<RowClickEvent> | Row click event | | rowDoubleClick | EventEmitter<any> | Row double-click event |

Methods

| Method | Returns | Description | | ---------------------- | ---------- | -------------------------------- | | reset() | void | Reset all filters and selections | | getSelectedRows() | any[] | Get selected rows | | getColumnFilters() | Column[] | Get column filter states | | clearSelectedRows() | void | Clear all selections | | selectRow(index) | void | Select row by index | | unselectRow(index) | void | Unselect row by index | | isRowSelected(index) | boolean | Check if row is selected |

🎨 Theming & Customization

CSS Custom Properties

NgxSimpleDatatable uses CSS custom properties for comprehensive theming:

:root {
  /* Primary Colors */
  --ngx-sdt-color-primary: #2563eb;
  --ngx-sdt-color-primary-hover: #1d4ed8;
  --ngx-sdt-color-primary-light: #dbeafe;

  /* Background Colors */
  --ngx-sdt-color-background: #ffffff;
  --ngx-sdt-color-background-gray: #f8fafc;

  /* Text Colors */
  --ngx-sdt-color-text: #1e293b;
  --ngx-sdt-color-text-muted: #64748b;

  /* Spacing */
  --ngx-sdt-spacing-sm: 0.5rem;
  --ngx-sdt-spacing-md: 0.75rem;
  --ngx-sdt-spacing-lg: 1rem;

  /* Typography */
  --ngx-sdt-font-size-sm: 0.875rem;
  --ngx-sdt-font-size-base: 0.875rem;
  --ngx-sdt-font-weight-medium: 500;

  /* Borders & Shadows */
  --ngx-sdt-border-radius-md: 0.5rem;
  --ngx-sdt-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
}

Built-in Themes

<!-- Dark theme -->
<ngx-simple-datatable class="dark-mode">
  <!-- Compact theme -->
  <ngx-simple-datatable class="ngx-sdt-theme-compact">
    <!-- Bootstrap compatibility -->
    <ngx-simple-datatable class="bs-compat">
      <!-- Tailwind CSS compatibility -->
      <ngx-simple-datatable class="tw-compat">
        <!-- Material Design compatibility -->
        <ngx-simple-datatable
          class="md-compat"
        ></ngx-simple-datatable></ngx-simple-datatable></ngx-simple-datatable></ngx-simple-datatable
></ngx-simple-datatable>

Framework Integration

Tailwind CSS

/* Custom Tailwind integration */
.my-datatable {
  @apply rounded-lg shadow-lg border border-gray-200;
  --ngx-sdt-color-primary: theme('colors.blue.600');
  --ngx-sdt-color-background: theme('colors.white');
  --ngx-sdt-border-radius-lg: theme('borderRadius.lg');
}

Bootstrap

<!-- Bootstrap classes work seamlessly -->
<ngx-simple-datatable class="table-responsive border rounded">
  <ng-template ngxSimpleDatatableSlot="status" let-data="data">
    <span class="badge bg-success">{{ data.status }}</span>
  </ng-template>
</ngx-simple-datatable>

📱 Responsive Design

NgxSimpleDatatable is mobile-first and automatically adapts to different screen sizes:

<!-- Enable mobile stack mode -->
<ngx-simple-datatable class="ngx-sdt-mobile-stack"></ngx-simple-datatable>

<!-- Responsive column sizing -->
<ngx-simple-datatable
  columnSizingStrategy="hybrid"
  [preserveReadability]="true"
  [allowHorizontalScroll]="true"
></ngx-simple-datatable>

Breakpoint Customization

.my-responsive-table {
  /* Custom breakpoints */
  --ngx-sdt-breakpoint-sm: 640px;
  --ngx-sdt-breakpoint-md: 768px;
  --ngx-sdt-breakpoint-lg: 1024px;
}

🔄 Migration Guide

From @bhplugin/ng-datatable

This library is inspired by and designed as a modern replacement for @bhplugin/ng-datatable. Here's how to migrate:

1. Installation

# Remove old package
npm uninstall @bhplugin/ng-datatable

# Install new package
npm install ngx-simple-datatable

2. Import Changes

// Before
import { DataTableModule } from '@bhplugin/ng-datatable';

// After
import { SimpleDatatableComponent } from 'ngx-simple-datatable';

@Component({
  standalone: true,
  imports: [SimpleDatatableComponent], // No module needed
})

3. Template Updates

<!-- Before -->
<ng-datatable [rows]="rows" [columns]="cols"></ng-datatable>

<!-- After -->
<ngx-simple-datatable [rows]="rows" [columns]="columns"></ngx-simple-datatable>

4. Column Definition Changes

// Before
cols: Array<colDef> = [{ field: 'name', title: 'Name' }];

// After
columns = signal<Column[]>([
  {
    field: 'name',
    title: 'Name',
    type: 'string',
    preferredWidth: '200px',
    minWidth: '120px',
  },
]);

5. Signal-based Reactivity

// Before
rows: Array<any> = [];

// After (recommended)
rows = signal<any[]>([]);

// Or keep existing approach
rows: any[] = [];

🛠️ Development

Prerequisites

  • Node.js 18+
  • Angular CLI 17+

Setup

git clone https://github.com/AngelCareaga/ngx-simple-datatable.git
cd ngx-simple-datatable
npm install

Development Server

npm start

Build Library

ng build ngx-simple-datatable

Run Tests

ng test

Code Formatting

This project uses Prettier for code formatting:

npm run format

🌍 Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)
  • Mobile browsers (iOS Safari, Chrome Mobile)

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Development Guidelines

  • Follow the existing code style
  • Add tests for new features
  • Update documentation for any API changes
  • Use conventional commit messages

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • @bhplugin/ng-datatable - Created by BH Plugin, which served as the primary inspiration for this modern Angular implementation
  • Angular Team - For the amazing framework and Angular 17+ features
  • Community Contributors - For feedback and feature requests

📞 Support


Made with ❤️ by Angel Careaga

⭐ Star this repo if you found it helpful!