<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/monokai-sublime.min.css" integrity="sha512-ade8vHOXH67Cm9z/U2vBpckPD1Enhdxl3N05ChXyFx5xikfqggrK4RrEele+VWY/iaZyfk7Bhk6CyZvlh7+5JQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
🌾 ng-oatv0.6.0Angular UI library

Data tables with typed columns. Supports clickable rows, empty state, horizontal scroll, and vertical scroll with sticky header.

InputTypeDefaultDescription
columnsNgOatTableColumn[]requiredColumn definitions
dataRecord<string, any>[]requiredRow data
clickablebooleanfalseEnable row click styling
emptyTextstring'No data available.'Text shown when data is empty
scrollXbooleanfalseEnable horizontal scroll — table overflows horizontally on small screens
scrollYstring'' Enable vertical scroll with a sticky header. Pass any CSS length: '300px', '50vh'
OutputTypeDescription
rowClickRecord<string, any>Emitted when a row is clicked
sortChangeNgOatTableSortChangeEmitted when a sortable column changes direction

Import & Usage

typescript
import { Component } from '@angular/core';
import { NgOatTable, type NgOatTableColumn } from '@letsprogram/ng-oat/table';

@Component({
  selector: 'app-example',
  imports: [NgOatTable],
  template: `
    <ng-oat-table
      [columns]="columns"
      [data]="users"
      [scrollX]="true"
      [clickable]="true"
      (rowClick)="onRowClick($event)" />
  `,
})
export class ExampleComponent {
  columns: NgOatTableColumn[] = [
    { key: 'name', label: 'Name' },
    { key: 'role', label: 'Role' },
  ];
  users = [
    { name: 'Alice', role: 'Engineer' },
    { name: 'Bob', role: 'Designer' },
  ];
  onRowClick(row: any) {
    console.log('Clicked:', row);
  }
}

Basic Table

Name Role Status
AliceEngineerActive
BobDesignerAway
CarolPMActive
DaveQAActive
html
<ng-oat-table
  [columns]="[
    { key: 'name', label: 'Name' },
    { key: 'role', label: 'Role' },
    { key: 'status', label: 'Status' }
  ]"
  [data]="users"
  [scrollX]="true" />

Clickable Rows

Name Role Status
AliceEngineerActive
BobDesignerAway
CarolPMActive
DaveQAActive
html
<ng-oat-table
  [columns]="columns"
  [data]="users"
  [scrollX]="true"
  [clickable]="true"
  (rowClick)="onRowClick($event)" />

Horizontal Scroll

Use [scrollX]="true" so wide tables stay within the layout and scroll horizontally on small screens instead of overflowing.

Full Name Email Role Department Location Date Joined Status
Alice Johnsonalice@example.comEngineerPlatformNew York2021-03-15Active
Bob Martinezbob@example.comDesignerProductAustin2022-07-01Away
Carol Singhcarol@example.comPMOperationsLondon2020-11-22Active
Dave Kimdave@example.comQAQualityToronto2023-01-10Active
html
<ng-oat-table
  [columns]="wideColumns"
  [data]="wideData"
  [scrollX]="true" />

Vertical Scroll + Sticky Header

Use [scrollY]="'260px'" to cap the table height. The header row stays fixed while the body scrolls.

Name Role Status
AliceEngineerActive
BobDesignerAway
CarolPMActive
DaveQAActive
EveDevOpsAway
FrankEngineerActive
GraceDesignerActive
HankQAAway
IrisPMActive
JackEngineerActive
KarenDevOpsAway
LeoDesignerActive
html
<ng-oat-table
  [columns]="columns"
  [data]="manyUsers"
  [scrollX]="true"
  scrollY="260px" />

Empty State

Name Role Status
No users found. Try adjusting your filters.
html
<ng-oat-table
  [columns]="columns"
  [data]="[]"
  [scrollX]="true"
  emptyText="No users found." />

Product Inventory

Product Price In Stock Category
Wireless Keyboard$49.99142Electronics
USB-C Hub$29.9958Accessories
Monitor Stand$79.9923Furniture
Desk Lamp$34.9976Furniture
Webcam Pro$89.9931Electronics
Cable Organizer$14.99204Accessories
Laptop Sleeve$24.9991Accessories
Mechanical Mouse$59.9947Electronics
html
<ng-oat-table
  [columns]="[
    { key: 'name', label: 'Product', width: '40%' },
    { key: 'price', label: 'Price' },
    { key: 'stock', label: 'In Stock' },
    { key: 'category', label: 'Category' }
  ]"
  [data]="products"
  [scrollX]="true" />

Sortable table with pagination

Sorting stays available while pagination keeps larger datasets easy to scan.

Category
Wireless Keyboard$49.99142Electronics
USB-C Hub$29.9958Accessories
Monitor Stand$79.9923Furniture
html
<ng-oat-table
  [columns]="sortableColumns"
  [data]="paginatedProducts()"
  [sortable]="true"
  [striped]="true" />

<ng-oat-pagination
  [totalPages]="productTotalPages()"
  [currentPage]="productPage()"
  (pageChange)="setProductPage($event)" />

Custom sort icon

Pass a template to use your own icon or icon component in sortable headers.

Category
Wireless Keyboard$49.99142Electronics
USB-C Hub$29.9958Accessories
Monitor Stand$79.9923Furniture
Desk Lamp$34.9976Furniture
Webcam Pro$89.9931Electronics
Cable Organizer$14.99204Accessories
Laptop Sleeve$24.9991Accessories
Mechanical Mouse$59.9947Electronics
html
<ng-template #customSortIcon let-direction let-active="active">
  <span [class.active]="active">
    {{ active ? (direction === 'asc' ? 'A-Z' : 'Z-A') : 'Sort' }}
  </span>
</ng-template>

<ng-oat-table
  [columns]="sortableColumns"
  [data]="products"
  [sortable]="true"
  [sortIcon]="customSortIcon" />

Search, sorting, and pagination

Use local filtering for small datasets or send the same search, page, and sort events to your API for larger datasets.

Category
Wireless Keyboard$49.99142Electronics
USB-C Hub$29.9958Accessories
Monitor Stand$79.9923Furniture
html
<ng-oat-search-input
  placeholder="Search products..."
  (search)="onClientSearch($event)" />

<ng-oat-table
  [columns]="sortableColumns"
  [data]="clientPageProducts()"
  [sortable]="true"
  [striped]="true" />

<ng-oat-pagination
  [totalPages]="clientTotalPages()"
  [currentPage]="clientPage()"
  (pageChange)="setClientPage($event)" />

Server-side search pattern

This example keeps only the current page in the table. Search, pagination, and sorting call one server-style loader.

Category
Wireless Keyboard$49.99142Electronics
USB-C Hub$29.9958Accessories
Monitor Stand$79.9923Furniture
html
<ng-oat-search-input
  placeholder="Search the catalog..."
  (search)="loadServerPage($event, 1)" />

<ng-oat-table
  [columns]="sortableColumns"
  [data]="serverPageRows()"
  [sortable]="true"
  (sortChange)="onServerSort($event)" />

<ng-oat-pagination
  [totalPages]="serverTotalPages()"
  [currentPage]="serverPage()"
  (pageChange)="loadServerPage(serverQuery(), $event)" />