Quick start
Install and first table
Using an AI assistant? Start with the /nat-best-practises skill so generated code follows the table API, state model, accessibility rules, and styling contract.
Recommended Agent Setup
Install the table package and Angular companion peers:
pnpm add ng-advanced-table @angular/aria @angular/cdk
# or: npm install ng-advanced-table @angular/aria @angular/cdk
# or: yarn add ng-advanced-table @angular/aria @angular/cdk
Keep @angular/core and @angular/common in your Angular app dependencies.
Install the agent skill:
npx skills add VaggelisKa/angular-advanced-table --skill nat-best-practises
Start by asking for the table contract:
Use /nat-best-practises to build an Angular table for invoices with columns for number, customer, status, and total. Start with the row type, row id, columns, and accessibility checks.
Review that contract before generating code.
Manual Setup
If you are wiring the table by hand, start with NatTable inside NatTableSurface.
First Table
Create rows and columns, then render NatTable inside NatTableSurface. Give every table an accessibleName or caption.
import { Component } from '@angular/core';
import { NatTable } from 'ng-advanced-table';
import { NatTableSurface } from 'ng-advanced-table/components';
interface PositionRow {
id: string;
symbol: string;
company: string;
}
@Component({
selector: 'app-positions-table',
imports: [NatTable, NatTableSurface],
template: `
<nat-table-surface>
<nat-table [data]="rows" [columns]="columns" accessibleName="Open positions" />
</nat-table-surface>
`
})
export class PositionsTable {
readonly rows: readonly PositionRow[] = [
{ id: 'pos-1', symbol: 'AAPL', company: 'Apple' },
{ id: 'pos-2', symbol: 'MSFT', company: 'Microsoft' }
];
readonly columns = [
{
accessorKey: 'symbol',
header: 'Symbol',
meta: { label: 'Symbol', rowHeader: true }
},
{
accessorKey: 'company',
header: 'Company',
meta: { label: 'Company' }
}
];
}
Rows with a string or number id property get stable table identity automatically. Use getRowId when identity lives somewhere else.
The table above is visually headless: it inherits page colors and system defaults. For the polished stock look, import 'ng-advanced-table/components/theme.css' once (see /docs/theming), or theme it yourself with --nat-table-* tokens.
Core-Only Scope
For a core-only table, provide NatTableService at the local wrapper that owns the table. Use NatTableSurface for the standard scoped controller and companion-control wiring.
import { Component } from '@angular/core';
import { NatTable, NatTableService } from 'ng-advanced-table';
interface PositionRow {
id: string;
symbol: string;
}
@Component({
selector: 'app-core-only-table',
imports: [NatTable],
providers: [NatTableService],
template: ` <nat-table [data]="rows" [columns]="columns" accessibleName="Core-only positions" /> `
})
export class CoreOnlyTable {
readonly rows: readonly PositionRow[] = [];
readonly columns = [
{
accessorKey: 'symbol',
header: 'Symbol',
meta: { label: 'Symbol', rowHeader: true }
}
];
}
Add Companion Controls
Use ng-advanced-table/components when you want pagination controls, column visibility, horizontal scroll controls, toolbar behavior, header actions, selection checkbox columns, or export actions.
import { Component, signal } from '@angular/core';
import { NatTable, type NatTableUserState } from 'ng-advanced-table';
import {
NatTableColumnVisibility,
NatTablePagination,
NatTableScrollControl,
NatTableSurface,
withNatTableHeaderActions
} from 'ng-advanced-table/components';
interface PositionRow {
id: string;
symbol: string;
desk: string;
price: number;
}
@Component({
selector: 'app-positions-table',
imports: [NatTable, NatTableColumnVisibility, NatTablePagination, NatTableScrollControl, NatTableSurface],
template: `
<nat-table-surface [enableSorting]="true" [enablePinning]="true" [initialState]="initialState">
<nat-table-pagination [pageSizeOptions]="[25, 50, 100]" />
<nat-table [data]="rows()" [columns]="columns" accessibleName="Open positions" />
<nat-table-scroll-control />
<nat-table-column-visibility />
</nat-table-surface>
`
})
export class PositionsTable {
readonly rows = signal<readonly PositionRow[]>([]);
readonly initialState: Partial<NatTableUserState> = {
pagination: { pageIndex: 0, pageSize: 25 }
};
readonly columns = withNatTableHeaderActions([
{
accessorKey: 'symbol',
header: 'Symbol',
meta: { label: 'Symbol', rowHeader: true }
},
{
accessorKey: 'desk',
header: 'Desk',
meta: { label: 'Desk' }
},
{
accessorKey: 'price',
header: 'Price',
meta: { label: 'Price', align: 'end' },
cell: (context) => `$${context.getValue<number>().toFixed(2)}`
}
]);
}
NatTableSurface provides the scoped table controller used by companion controls. Controls inside the same surface can read table state, patch state, bind aria-controls, and resolve locale labels without extra wiring.
Authoring Defaults
Start with these defaults unless the feature needs something else:
| Need | Default choice |
|---|---|
| Table identity | accessibleName or visible caption |
| Row identity | String or number row.id; getRowId for custom, composite, or nested identifiers |
| Column labels | meta.label on every column |
| Row header | meta.rowHeader: true on the primary identifying column |
| Numeric columns | meta.align: 'end' |
| Initial page size or sort | [initialState] |
| Persisting one state slice | [state] with only that slice plus the matching *Change output |
| Search and domain filters | Consumer-owned controls that patch table state |
| Loading, empty, and error | dataStatus plus natTableLoading, natTableEmpty, or natTableError templates |
Next Steps
- Use
/docs/columnsfor column metadata, sizing, custom cell components, header actions, and row activation. - Use
/docs/statefor controlled and uncontrolled state patterns. - Use
/docs/data-lifecyclefor loading, empty, error, background refresh, and Manual Data Handling. - Use
/docs/filtering-searchfor search and filtering controls. - Use
/docs/row-selectionfor selection checkboxes and bulk state. - Use
/docs/exportfor CSV defaults and custom export handlers.