Data display

Data Table
v1.0.9
Ready for Production

Build feature-rich, accessible data tables with sorting, filtering, pagination, row selection, and advanced interactions powered by TanStack Table.

Prefer AI-assisted development?

This documentation is available via the Catalyst MCP Server. Learn how to connect →

Catalyst Data Table provides a suite of composable UI components that integrate with TanStack Table v8 — giving you styled, accessible table primitives for sorting, expanding, row/column pinning, column resizing, row selection, and pagination while TanStack Table manages all state and logic.

Preview
First Name
Last Name
Age
Visits
Progress
John
Doe
28
543
75
Jane
Smith
34
892
92
Bob
Johnson
45
234
45
Alice
Williams
29
678
88
Charlie
Brown
52
156
34
Diana
Davis
31
789
67
Eve
Miller
27
445
56
Frank
Wilson
38
921
91

Installation

npm install @pmi/catalyst-data-table

Note: @tanstack/react-table (v8.20.6) is a direct dependency bundled with this package — no separate install required.

import { useReactTable, getCoreRowModel, type ColumnDef } from '@tanstack/react-table';
import {
  DataTableRoot,
  DataTableRow,
  DataTableHead,
  DataTableCell,
  DataTableFlexRender,
} from '@pmi/catalyst-data-table';

The Data Table is built on a compound component pattern. The typical JSX structure is:

<DataTableRoot table={table}>
  <thead>
    <tr>
      <DataTableHead header={header}>
        <DataTableFlexRender header={header} />
      </DataTableHead>
    </tr>
  </thead>
  <tbody>
    <DataTableRow row={row}>
      <DataTableCell cell={cell}>
        <DataTableFlexRender cell={cell} />
      </DataTableCell>
    </DataTableRow>
  </tbody>
</DataTableRoot>

Data Table components require a TanStack Table instance created with useReactTable. Enable features by composing row models:

import {
  useReactTable,
  getCoreRowModel,
  getSortedRowModel,
  getExpandedRowModel,
  getPaginationRowModel,
  type ColumnDef,
} from '@tanstack/react-table';

const table = useReactTable({
  data,
  columns,
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(),        // sorting
  getSubRows: (row) => row.subRows,              // expanding
  getExpandedRowModel: getExpandedRowModel(),    // expanding
  getPaginationRowModel: getPaginationRowModel(), // pagination
  columnResizeMode: 'onChange',                  // column resizing
});

Always wrap data and columns in useMemo to prevent unnecessary re-renders.

Common Patterns

Sorting

Click column headers to toggle ascending, descending, or no sort. The sequence is asc → desc → none.

Preview
John
Doe
28
543
75
Jane
Smith
34
892
92
Bob
Johnson
45
234
45
Alice
Williams
29
678
88
Charlie
Brown
52
156
34
Diana
Davis
31
789
67
Eve
Miller
27
445
56
Frank
Wilson
38
921
91

Expanding

Click the chevron icon to expand a row and reveal sub-rows. Sub-rows display with adjusted background color reflecting their depth.

Preview
expand
First Name
Last Name
Age
Visits
Progress
John
Doe
28
543
75
Alice
Williams
34
892
92
Charlie
Brown
45
234
45
Diana
Davis
31
789
67
Frank
Wilson
38
921
91

Row Selection

Select rows by clicking the checkbox or the row itself. The header checkbox toggles all rows; when some rows are selected it enters an indeterminate state.

Preview
First Name
Last Name
Age
Visits
Progress
John
Doe
28
543
75
Jane
Smith
34
892
92
Bob
Johnson
45
234
45
Alice
Williams
29
678
88
Charlie
Brown
52
156
34
Diana
Davis
31
789
67
Eve
Miller
27
445
56
Frank
Wilson
38
921
91

Row Pinning

Pin rows to the top or bottom of the table. Pinned rows remain sticky during vertical scroll.

Preview
📌
First Name
Last Name
Age
Visits
Progress
John
Doe
20
100
10
Jane
Smith
21
117
23
Bob
Johnson
22
134
36
Alice
Williams
23
151
49
Charlie
Brown
24
168
62
Diana
Davis
25
185
75
Eve
Miller
26
202
88
Frank
Wilson
27
219
11
John
Doe
28
236
24
Jane
Smith
29
253
37
Bob
Johnson
30
270
50
Alice
Williams
31
287
63
Charlie
Brown
32
304
76
Diana
Davis
33
321
89
Eve
Miller
34
338
12
Frank
Wilson
35
355
25
John
Doe
36
372
38
Jane
Smith
37
389
51
Bob
Johnson
38
406
64
Alice
Williams
39
423
77

Column Pinning

Pin columns to the left or right. Pinned columns stay fixed during horizontal scroll.

Preview
📌
First Name
📌
Last Name
📌
Age
📌
Visits
📌
Progress
John
Doe
28
543
75
Jane
Smith
34
892
92
Bob
Johnson
45
234
45
Alice
Williams
29
678
88
Charlie
Brown
52
156
34
Diana
Davis
31
789
67
Eve
Miller
27
445
56
Frank
Wilson
38
921
91

Column Resizing

Drag the resizer handle at a column's edge to adjust its width. Double-click the resizer to reset to the default size.

The resizer button is fully keyboard-operable: focus it with Tab, then use ArrowLeft / ArrowRight to adjust the column width in 10 px steps. Hold Shift while pressing an arrow key to move in 50 px steps. Press Enter to reset the column to its default width. This keyboard behaviour is required for accessibility compliance (WCAG 2.2 SC 2.1.1).

Preview
First Name
Last Name
Age
Visits
Progress
John
Doe
28
543
75
Jane
Smith
34
892
92
Bob
Johnson
45
234
45
Alice
Williams
29
678
88
Charlie
Brown
52
156
34
Diana
Davis
31
789
67
Eve
Miller
27
445
56
Frank
Wilson
38
921
91

Pagination

Client-side pagination using TanStack Table's getPaginationRowModel, combined with Catalyst Pagination and Select components.

Preview
First Name
Last Name
Age
Visits
Progress
John
Doe
20
100
10
Jane
Smith
21
117
23
Bob
Johnson
22
134
36
Alice
Williams
23
151
49
Charlie
Brown
24
168
62
Diana
Davis
25
185
75
Eve
Miller
26
202
88
Frank
Wilson
27
219
11
John
Doe
28
236
24
Jane
Smith
29
253
37

API Reference

Data Table is a compound component built on TanStack Table v8. Each part wraps a native HTML element and accepts a TanStack Table instance to drive its behaviour. The sections below summarize the API surface for each part.

DataTableRoot

Container that links the table UI to the TanStack Table instance. Forwards ref to HTMLTableElement. Extends all standard HTML <table> props.

Prop

Type

DataTableHead

Renders header cells with sorting, pinning, and resizing support. Forwards ref to HTMLTableCellElement. Automatically sets aria-sort based on sort state. Provides data-sorted and data-pinned data attributes for styling. Extends all standard HTML <th> props.

Prop

Type

DataTableRow

Renders rows with selection, expansion, and pinning support. Forwards ref to HTMLTableRowElement. Adds data-selected, data-subrow, and data-pinned data attributes. Extends all standard HTML <tr> props.

Prop

Type

DataTableCell

Renders cells with column-pinning support. Forwards ref to HTMLTableCellElement. Adds data-row-pinned and data-column-pinned data attributes. Extends all standard HTML <td> props.

Prop

Type

DataTableFlexRender

Dynamically renders cell or header content using TanStack Table's flexRender. Forwards ref to HTMLDivElement. Provide either cell or header — not both. Extends all standard HTML <div> props.

Prop

Type

DataTableSorting

Button that toggles column sorting when clicked. Must be used inside DataTableHead. Disabled automatically when the column cannot be sorted. Forwards ref to HTMLButtonElement. Extends all standard HTML <button> props.

Prop

Type

DataTableExpand

Button that toggles row expansion for hierarchical data. Returns null when the row cannot be expanded. Forwards ref to HTMLButtonElement. Adds data-expanded data attribute. Extends all standard HTML <button> props.

Prop

Type

DataTableRowPin

Button that pins or unpins a row to the top or bottom. Returns null when the row cannot be pinned or is already in the requested position. Forwards ref to HTMLButtonElement. Extends all standard HTML <button> props.

Prop

Type

DataTableColumnPin

Button that pins or unpins a column to the left or right. Must be used inside DataTableHead. Returns null when the column cannot be pinned or is already in the requested position. Forwards ref to HTMLButtonElement. Extends all standard HTML <button> props.

Prop

Type

DataTableColumnResizer

Draggable handle for adjusting column width. Must be used inside DataTableHead. Returns null when the column cannot be resized. Double-click to reset to default size. Forwards ref to HTMLButtonElement. Extends all standard HTML <button> props.

Prop

Type

Accessibility

Data Table is designed to meet WCAG 2.2 AA standards through semantic HTML and ARIA attributes.

Keyboard Interactions

KeyAction
TabMove focus between interactive controls (sort buttons, checkboxes, resizers, pin buttons)
Enter / SpaceActivate the focused interactive control
ArrowLeft / ArrowRightWhen a column resizer is focused: decrease / increase column width by 10 px
Shift + ArrowLeft / ArrowRightWhen a column resizer is focused: decrease / increase column width by 50 px
Enter (resizer focused)Reset the column to its default width
Arrow keys (other contexts)Not handled by the component — browser/AT behaviour varies; implement explicit keyboard handling if cell-level arrow navigation is required

ARIA

  • DataTableHead automatically applies aria-sort="ascending", aria-sort="descending", or aria-sort="none" on sortable columns (WCAG 2.2 SC 4.1.2).
  • DataTableHead sets scope="col" and role="columnheader" on every header cell for correct screen reader table navigation.
  • All interactive controls (DataTableSorting, DataTableExpand, DataTableRowPin, DataTableColumnPin, DataTableColumnResizer) render as <button> elements and are keyboard reachable.
  • Always provide visible labels or <span className="sr-only"> on icon-only controls so screen readers can announce their purpose (e.g. "expand row 1", "pin column firstName left").
  • Row selection checkboxes should carry aria-label values that identify the row (e.g. aria-label="select row 1").

Choosing the Right Component

If you need…Use instead
A simple read-only list of itemsA plain <ul> or <ol>
Lightweight display table with no interactionNative HTML <table> with Tailwind utilities
Paginated navigation controls onlyPagination
Filterable option listSelect or Autocomplete

On this page