Free
Pro

Data Table

Base UI (Angular) data-table (Pro) is an ops table: sort, page, select, resize, optional virtualize, serverSide mode, and cell templates via ng-template baseTableCell. Copy it in, pass columns and data, and handle pageChange when the server owns the slice. Pair with httpResource for server paging. Cookbooks: invoice-table, http-resource.

When to use

  • Admin and billing grids with selection, bulk actions, and status badges.
  • Server-driven pages — set serverSide and feed the current page into data.

When not to use

  • Inline cell editors or nested tables — project a cell template for badges and actions, but keep editing in a drawer or dialog.
  • A simple HTML table of static copy — use free table (`npx base-ui-cli add table`) instead of this Pro grid.

Install with npx base-ui-cli add data-table.

Pro@defer

Data Table — part of Base UI Pro

Unlock it plus 90 pro blocks, widgets & layouts — $99 one-time. Lifetime updates, 14-day money-back guarantee.

Unlock Pro

Playground

ID
Name
Email
Role
Status
Joined
1 Alice Johnson [email protected] Admin Active 2024-01-15
2 Bob Smith [email protected] Editor Active 2024-02-20
3 Carol White [email protected] Viewer Inactive 2024-03-10
4 David Brown [email protected] Editor Active 2024-04-05
5 Eve Davis [email protected] Admin Active 2024-05-12
1–5 of 12

Playground

HTML

<base-data-table
  [columns]="columns"
  [data]="users"
  sortable
  [striped]="true"
  [bordered]="true"
  [pageable]="true"
  [hoverable]="true"
  [selectable]="false"
  [resizable]="false">
</base-data-table>

Basic Table

Define [columns] as an array of TableColumn objects and pass [data] as an array of objects.

ID
Name
Email
Role
Status
Joined
1 Alice Johnson [email protected] Admin Active 2024-01-15
2 Bob Smith [email protected] Editor Active 2024-02-20
3 Carol White [email protected] Viewer Inactive 2024-03-10
4 David Brown [email protected] Editor Active 2024-04-05
5 Eve Davis [email protected] Admin Active 2024-05-12
1–5 of 12

Column Configuration

Columns support key, label, sortable, width, and align ('left' | 'center' | 'right'). Cells default to row[column.key]. Project ng-template baseTableCell="key" to render a badge, a button, or any other widget without forking the table. Import TableCellDirective next to DataTableComponent. Interactive cells should call $event.stopPropagation() so they do not also fire rowClick.

typescript

Cell templates

Match baseTableCell to a column key. Context: let-row, let-value="value", let-column="column", let-index="index". Columns without a template still interpolate the raw value.

Name
Email
Status
Alice Johnson [email protected] Active
Bob Smith [email protected] Active
Carol White [email protected] Inactive
David Brown [email protected] Active
Eve Davis [email protected] Active

Loading State

Set [loading]="true" to show skeleton rows while data loads. The data table will render animated placeholder rows matching your column count.

ID
Name
Email
Role
Status
Joined
1 Alice Johnson [email protected] Admin Active 2024-01-15
2 Bob Smith [email protected] Editor Active 2024-02-20
3 Carol White [email protected] Viewer Inactive 2024-03-10
4 David Brown [email protected] Editor Active 2024-04-05
5 Eve Davis [email protected] Admin Active 2024-05-12
6 Frank Miller [email protected] Viewer Active 2024-06-18
7 Grace Wilson [email protected] Editor Inactive 2024-07-22
8 Hank Taylor [email protected] Viewer Active 2024-08-30
9 Ivy Anderson [email protected] Admin Active 2024-09-14
10 Jack Thomas [email protected] Editor Inactive 2024-10-01
11 Karen Martinez [email protected] Viewer Active 2024-11-05
12 Leo Garcia [email protected] Admin Active 2024-12-10

Styling Options

Striped rows + Bordered

ID
Name
Email
Role
Status
Joined
1 Alice Johnson [email protected] Admin Active 2024-01-15
2 Bob Smith [email protected] Editor Active 2024-02-20
3 Carol White [email protected] Viewer Inactive 2024-03-10
4 David Brown [email protected] Editor Active 2024-04-05
5 Eve Davis [email protected] Admin Active 2024-05-12

No stripe, no border

ID
Name
Email
Role
Status
Joined
1 Alice Johnson [email protected] Admin Active 2024-01-15
2 Bob Smith [email protected] Editor Active 2024-02-20
3 Carol White [email protected] Viewer Inactive 2024-03-10
4 David Brown [email protected] Editor Active 2024-04-05
5 Eve Davis [email protected] Admin Active 2024-05-12

Empty State

When data is empty, a friendly message is shown. Customize it with emptyMessage, or project ng-template baseTableEmpty for a richer empty row. App-wide defaults come from provideBaseUiI18n().

ID
Name
Email
Role
Status
Joined

No users found matching your filters.

Error

Keep the table shell and put the failure in an alert above it. Reuse emptyMessage when the request returned no rows after an error retry.

Could not load users. Check the network and try again.
ID
Name
Email
Role
Status
Joined
No users loaded.

Row selection

Set selectable and bind [(selected)] to an array of rowKey values (defaults to id). Header checkbox selects the current page. selectionChange emits the selected row objects.

Selected ids: none

ID
Name
Email
Role
Status
Joined
1 Alice Johnson [email protected] Admin Active 2024-01-15
2 Bob Smith [email protected] Editor Active 2024-02-20
3 Carol White [email protected] Viewer Inactive 2024-03-10
4 David Brown [email protected] Editor Active 2024-04-05
5 Eve Davis [email protected] Admin Active 2024-05-12
1–5 of 12

Column resize

Set resizable and drag the right edge of a header. Lock a column with resizable: false on the column definition. Initial widths come from column.width.

ID
Name
Email
Role
Status
Joined
1 Alice Johnson [email protected] Admin Active 2024-01-15
2 Bob Smith [email protected] Editor Active 2024-02-20
3 Carol White [email protected] Viewer Inactive 2024-03-10
4 David Brown [email protected] Editor Active 2024-04-05
5 Eve Davis [email protected] Admin Active 2024-05-12
6 Frank Miller [email protected] Viewer Active 2024-06-18

Server page and sort

Set serverSide so the table does not slice or sort locally. Pass the current page in data, the full count in totalItems, and reload from pageChange / sortChange. Drive those events from Angular httpResource in the httpResource cookbook. Below-fold tables defer with a skeleton in the @defer cookbook.

ID
Name
Email
Role
Status
Joined
1 User 1 [email protected] Admin Active 2024-01-15
2 User 2 [email protected] Editor Inactive 2024-02-15
3 User 3 [email protected] Viewer Active 2024-03-15
4 User 4 [email protected] Admin Inactive 2024-04-15
5 User 5 [email protected] Editor Active 2024-05-15
6 User 6 [email protected] Viewer Inactive 2024-06-15
7 User 7 [email protected] Admin Active 2024-07-15
8 User 8 [email protected] Editor Inactive 2024-08-15
1–8 of 87

Virtualize

Set virtualize for large in-memory lists. Rows are windowed inside a fixed-height viewport. Pair with rowHeight matching the rendered row.

ID
Name
Email
Role
Status
Joined
1 User 1 [email protected] Admin Active 2024-01-15
2 User 2 [email protected] Editor Inactive 2024-02-15
3 User 3 [email protected] Viewer Active 2024-03-15
4 User 4 [email protected] Admin Inactive 2024-04-15
5 User 5 [email protected] Editor Active 2024-05-15
6 User 6 [email protected] Viewer Inactive 2024-06-15
7 User 7 [email protected] Admin Active 2024-07-15
8 User 8 [email protected] Editor Inactive 2024-08-15
9 User 9 [email protected] Viewer Active 2024-09-15
10 User 10 [email protected] Admin Inactive 2024-10-15
11 User 11 [email protected] Editor Active 2024-11-15
12 User 12 [email protected] Viewer Inactive 2024-12-15
13 User 13 [email protected] Admin Active 2024-01-15
14 User 14 [email protected] Editor Inactive 2024-02-15
15 User 15 [email protected] Viewer Active 2024-03-15
16 User 16 [email protected] Admin Inactive 2024-04-15

Keyboard & accessibility

Role
HTML table. Sortable headers are buttons. Selectable rows expose checkboxes.
Focus
Tab moves through headers, row selection, and pagination. Loading replaces body cells with skeletons.

Shortcuts

  • TabMove through sortable headers, row checkboxes, and pager
  • EnterToggle sort on a header button
  • SpaceToggle the focused row checkbox when selectable

Site-wide VPAT-style notes live on the accessibility report.

Unit tests: copy DataTableHarness with the component and load it with TestbedHarnessEnvironment.loader(fixture). See Getting started — Testing.

Installation

Run the following command to add this component to your project:

bash

npx base-ui-cli add data-table

API Reference

For AI agents

Copy a prompt with the registry name, CLI install, and import — or add the Base UI MCP server.

bash

npx -y base-ui-ng-mcp

Base UI provides standalone components. Import the exact elements you want to use into your component.

typescript (Example)

// Install: npx base-ui-cli add data-table
// Paths are relative to aliases.components (default: src/app/components)
import { DataTableComponent } from './data-table/data-table.component';
import { TableCellContext, TableCellDirective } from './data-table/table-cell.directive';
import { TableEmptyDirective } from './data-table/table-empty.directive';

@Component({
  selector: 'app-your-component',
  imports: [
    DataTableComponent,
    TableCellDirective,
    TableEmptyDirective
  ],
  template: `...`
})
export class YourComponent {}

API for data-table — generated from JSDoc in the library source.

API reference for data-table
APIMemberTypeDefaultDescription
TableCellContext$implicitT
TableCellContextrowT
TableCellContextcolumnTableColumn
TableCellContextvalueunknown
TableCellContextindexnumber
base-data-tableclassstring''Extra host classes merged via `cn()`.
base-data-tablecolumnsTableColumn[][]Column definitions (`key`, `label`, optional `sortable` / `width` / `align`). Cells default to `row[key]`. Override a column with `<ng-template baseTableCell="key">`.
base-data-tabledataT[][]Row objects. When `serverSide` is set, pass the current page only.
base-data-tablesortablebooleanfalseEnables header click sorting for columns with `sortable: true`.
base-data-tablepageablebooleanfalseShows the paginator when the row count exceeds `pageSize`.
base-data-tablepageSizenumber10Rows per page (client slice, or the page size advertised to the server).
base-data-tableloadingbooleanfalseShows skeleton rows instead of data.
base-data-tablestripedbooleanfalseAlternating row background.
base-data-tableborderedbooleanfalseOuter and row borders.
base-data-tablehoverablebooleantrueRow hover highlight. Defaults to true.
base-data-tableemptyMessagestringMessage shown when `data` is empty and not loading. Replaced by `baseTableEmpty` when projected. When omitted, uses `provideBaseUiI18n().noDataAvailable`.
base-data-tableselectablebooleanfalseAdds a checkbox column. Bind `selected` to an array of `rowKey` values.
base-data-tablerowKeyunknown'id'Property used as the selection identity. Defaults to `'id'`.
base-data-tableselected(string | number)[][]Selected row ids (or whatever `rowKey` points at). Two-way bindable.
base-data-tableresizablebooleanfalseDrag the header edge to resize columns. Uses `column.width` as the start width.
base-data-tableserverSidebooleanfalseSkip client sort/slice. Parent fetches; pass the current page in `data` and the full count in `totalItems`.
base-data-tabletotalItemsnumber0Total rows across all pages. Required for the paginator when `serverSide` is set.
base-data-tablevirtualizebooleanfalseWindow rows in a fixed-height viewport. Best with `pageable` off and large `data`.
base-data-tablerowHeightnumber44Fixed row height in pixels used for windowing. Must match the rendered row.
base-data-tableviewportHeightnumber400Viewport height in pixels when `virtualize` is set.
base-data-tablecurrentPagenumber1Current page (1-based). Two-way bindable for server-driven tables.
base-data-table(rowClick)TEmits the clicked row. Checkbox clicks do not fire this.
base-data-table(sortChange)DataTableSortChangeEmits after the user toggles a sortable header.
base-data-table(pageChange)DataTablePageChangeEmits when the paginator changes page. Always fired in `serverSide` mode.
base-data-table(selectionChange)T[]Emits the selected row objects whenever the checkbox column changes.
[baseTableCell]baseTableCellstring(required)`TableColumn.key` this template renders.
[baseTableEmpty]Marks an `ng-template` as the empty-state body for . When present, it replaces `emptyMessage` in the empty row.