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 alice@example.com Admin Active 2024-01-15
2 Bob Smith bob@example.com Editor Active 2024-02-20
3 Carol White carol@example.com Viewer Inactive 2024-03-10
4 David Brown david@example.com Editor Active 2024-04-05
5 Eve Davis eve@example.com 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 alice@example.com Admin Active 2024-01-15
2 Bob Smith bob@example.com Editor Active 2024-02-20
3 Carol White carol@example.com Viewer Inactive 2024-03-10
4 David Brown david@example.com Editor Active 2024-04-05
5 Eve Davis eve@example.com 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 alice@example.com Active
Bob Smith bob@example.com Active
Carol White carol@example.com Inactive
David Brown david@example.com Active
Eve Davis eve@example.com 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 alice@example.com Admin Active 2024-01-15
2 Bob Smith bob@example.com Editor Active 2024-02-20
3 Carol White carol@example.com Viewer Inactive 2024-03-10
4 David Brown david@example.com Editor Active 2024-04-05
5 Eve Davis eve@example.com Admin Active 2024-05-12
6 Frank Miller frank@example.com Viewer Active 2024-06-18
7 Grace Wilson grace@example.com Editor Inactive 2024-07-22
8 Hank Taylor hank@example.com Viewer Active 2024-08-30
9 Ivy Anderson ivy@example.com Admin Active 2024-09-14
10 Jack Thomas jack@example.com Editor Inactive 2024-10-01
11 Karen Martinez karen@example.com Viewer Active 2024-11-05
12 Leo Garcia leo@example.com Admin Active 2024-12-10

Styling Options

Striped rows + Bordered

ID
Name
Email
Role
Status
Joined
1 Alice Johnson alice@example.com Admin Active 2024-01-15
2 Bob Smith bob@example.com Editor Active 2024-02-20
3 Carol White carol@example.com Viewer Inactive 2024-03-10
4 David Brown david@example.com Editor Active 2024-04-05
5 Eve Davis eve@example.com Admin Active 2024-05-12

No stripe, no border

ID
Name
Email
Role
Status
Joined
1 Alice Johnson alice@example.com Admin Active 2024-01-15
2 Bob Smith bob@example.com Editor Active 2024-02-20
3 Carol White carol@example.com Viewer Inactive 2024-03-10
4 David Brown david@example.com Editor Active 2024-04-05
5 Eve Davis eve@example.com 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 alice@example.com Admin Active 2024-01-15
2 Bob Smith bob@example.com Editor Active 2024-02-20
3 Carol White carol@example.com Viewer Inactive 2024-03-10
4 David Brown david@example.com Editor Active 2024-04-05
5 Eve Davis eve@example.com 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 alice@example.com Admin Active 2024-01-15
2 Bob Smith bob@example.com Editor Active 2024-02-20
3 Carol White carol@example.com Viewer Inactive 2024-03-10
4 David Brown david@example.com Editor Active 2024-04-05
5 Eve Davis eve@example.com Admin Active 2024-05-12
6 Frank Miller frank@example.com 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 user1@example.com Admin Active 2024-01-15
2 User 2 user2@example.com Editor Inactive 2024-02-15
3 User 3 user3@example.com Viewer Active 2024-03-15
4 User 4 user4@example.com Admin Inactive 2024-04-15
5 User 5 user5@example.com Editor Active 2024-05-15
6 User 6 user6@example.com Viewer Inactive 2024-06-15
7 User 7 user7@example.com Admin Active 2024-07-15
8 User 8 user8@example.com 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 user1@example.com Admin Active 2024-01-15
2 User 2 user2@example.com Editor Inactive 2024-02-15
3 User 3 user3@example.com Viewer Active 2024-03-15
4 User 4 user4@example.com Admin Inactive 2024-04-15
5 User 5 user5@example.com Editor Active 2024-05-15
6 User 6 user6@example.com Viewer Inactive 2024-06-15
7 User 7 user7@example.com Admin Active 2024-07-15
8 User 8 user8@example.com Editor Inactive 2024-08-15
9 User 9 user9@example.com Viewer Active 2024-09-15
10 User 10 user10@example.com Admin Inactive 2024-10-15
11 User 11 user11@example.com Editor Active 2024-11-15
12 User 12 user12@example.com Viewer Inactive 2024-12-15
13 User 13 user13@example.com Admin Active 2024-01-15
14 User 14 user14@example.com Editor Inactive 2024-02-15
15 User 15 user15@example.com Viewer Active 2024-03-15
16 User 16 user16@example.com 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.