structyl

DataTable

stable

A full-featured data grid with a rich column definition API, tree data, copy/paste, density, bulk actions, row action menus, custom slots, search, nested filters, virtualization, pinning, grouping, aggregation and more.

Basic usage

Name
Email
Role
Team
Status
Revenue
Cost
Score
Row total
Actions
Ada Lovelace
ada@example.com
Admin
Platform
Active
1,800
920
91
2720
Grace Hopper
grace@example.com
Admin
Growth
Active
2,100
990
88
3090
Katherine Johnson
katherine@example.com
Owner
Support
Invited
1,500
760
82
2260
Total540089091
3 rows
Page 1 of 1

Examples

Search, filters and pagination

Global search, column filter state, nested AND/OR filters, selection and pagination can run locally or be mirrored to a server adapter.

Project
Owner
Status
Budget
Revenue
Cost
Progress
Workspace 1
Ada Lovelace
Healthy
$12k
1,500
700
35
Workspace 5
Ada Lovelace
Healthy
$24k
1,980
1,000
63
Workspace 6
Grace Hopper
Review
$27k
2,100
1,075
70
Workspace 7
Margaret Hamilton
Blocked
$30k
2,220
1,150
77
Workspace 8
Alan Turing
Queued
$33k
2,340
1,225
84
Workspace 9
Ada Lovelace
Healthy
$36k
2,460
1,300
91
Workspace 13
Ada Lovelace
Healthy
$48k
2,940
1,600
59
Workspace 15
Margaret Hamilton
Blocked
$54k
3,180
1,750
73
13 rows
Page 1 of 2

Virtual rows and columns

Use row and column virtualization together for unlimited-feeling datasets without rendering every cell.

Project
Owner
Status
Budget
Revenue
Cost
Progress
M1
M2
M3
M4
M5
M6
M7
Workspace 1
Ada Lovelace
Healthy
$12k
1,500
700
20
20
21
22
23
24
25
26
Workspace 2
Grace Hopper
Review
$15k
1,533
719
31
31
32
33
34
35
36
37
Workspace 3
Margaret Hamilton
Blocked
$18k
1,566
738
42
42
43
44
45
46
47
48
Workspace 4
Alan Turing
Queued
$21k
1,599
757
53
53
54
55
56
57
58
59
Workspace 5
Ada Lovelace
Healthy
$24k
1,632
776
64
64
65
66
67
68
69
70
Workspace 6
Grace Hopper
Review
$27k
1,665
795
75
75
76
77
78
79
80
81
Workspace 7
Margaret Hamilton
Blocked
$30k
1,698
814
86
86
87
88
89
90
91
92
Workspace 8
Alan Turing
Queued
$33k
1,731
833
97
97
98
99
100
101
102
103
Workspace 9
Ada Lovelace
Healthy
$36k
1,764
852
28
28
29
30
31
32
33
34
Workspace 10
Grace Hopper
Review
$39k
1,797
871
39
39
40
41
42
43
44
45
Workspace 11
Margaret Hamilton
Blocked
$42k
1,830
890
50
50
51
52
53
54
55
56
Workspace 12
Alan Turing
Queued
$45k
1,863
909
61
61
62
63
64
65
66
67

Configuration, pinning and actions

Column configuration, column selection, row pinning, column pinning, grouping, row actions and detail panels are built in.

Project
Owner
Status
Budget
Revenue
Cost
Progress
Actions
Workspace 1
Ada Lovelace
Healthy
$12k
1,500
700
35
Workspace 2
Grace Hopper
Review
$15k
1,620
775
42
Workspace 3
Margaret Hamilton
Blocked
$18k
1,740
850
49
Workspace 4
Alan Turing
Queued
$21k
1,860
925
56
Workspace 5
Ada Lovelace
Healthy
$24k
1,980
1,000
63
Workspace 6
Grace Hopper
Review
$27k
2,100
1,075
70
Workspace 7
Margaret Hamilton
Blocked
$30k
2,220
1,150
77
Workspace 8
Alan Turing
Queued
$33k
2,340
1,225
84
Workspace 9
Ada Lovelace
Healthy
$36k
2,460
1,300
91
Workspace 10
Grace Hopper
Review
$39k
2,580
1,375
38
Workspace 11
Margaret Hamilton
Blocked
$42k
2,700
1,450
45
Workspace 12
Alan Turing
Queued
$45k
2,820
1,525
52
Workspace 13
Ada Lovelace
Healthy
$48k
2,940
1,600
59
Workspace 14
Grace Hopper
Review
$51k
3,060
1,675
66
Workspace 15
Margaret Hamilton
Blocked
$54k
3,180
1,750
73
Workspace 16
Alan Turing
Queued
$57k
3,300
1,825
80
Workspace 17
Ada Lovelace
Healthy
$60k
3,420
1,900
87
Workspace 18
Grace Hopper
Review
$63k
3,540
1,975
94
Workspace 19
Margaret Hamilton
Blocked
$66k
3,660
2,050
41
Workspace 20
Alan Turing
Queued
$69k
3,780
2,125
48
Workspace 21
Ada Lovelace
Healthy
$72k
3,900
2,200
55
Workspace 22
Grace Hopper
Review
$75k
4,020
2,275
62
Workspace 23
Margaret Hamilton
Blocked
$78k
4,140
2,350
69
Workspace 24
Alan Turing
Queued
$81k
4,260
2,425
76

Totals, spanning and row configuration

Footer aggregations, row totals, cell colSpan/rowSpan and row-level classes cover analytical grids.

Project
Owner
Status
Budget
Revenue
Cost
Progress
Row total
Workspace 1
Ada Lovelace
Healthy
$12k
1,500
700
35
2200
Workspace 2
Grace Hopper
Review
$15k
1,620
775
42
2395
Workspace 3
Blocked
$18k
1,740
850
49
2590
Workspace 4
Alan Turing
Queued
$21k
1,860
925
56
2785
Workspace 5
Ada Lovelace
Healthy
$24k
1,980
1,000
63
2980
Workspace 6
Grace Hopper
Review
$27k
2,100
1,075
70
3175
Workspace 7
Blocked
$30k
2,220
1,150
77
3370
Workspace 8
Alan Turing
Queued
$33k
2,340
1,225
84
3565
Workspace 9
Ada Lovelace
Healthy
$36k
2,460
1,300
91
3760
Workspace 10
Grace Hopper
Review
$39k
2,580
1,375
38
3955
Workspace 11
Blocked
$42k
2,700
1,450
45
4150
Workspace 12
Alan Turing
Queued
$45k
2,820
1,525
52
4345
Workspace 13
Ada Lovelace
Healthy
$48k
2,940
1,600
59
4540
Workspace 14
Grace Hopper
Review
$51k
3,060
1,675
66
4735
Workspace 15
Blocked
$54k
3,180
1,750
73
4930
Workspace 16
Alan Turing
Queued
$57k
3,300
1,825
80
5125
Workspace 17
Ada Lovelace
Healthy
$60k
3,420
1,900
87
5320
Workspace 18
Grace Hopper
Review
$63k
3,540
1,975
94
5515
Workspace 19
Blocked
$66k
3,660
2,050
41
5710
Workspace 20
Alan Turing
Queued
$69k
3,780
2,125
48
5905
Workspace 21
Ada Lovelace
Healthy
$72k
3,900
2,200
55
6100
Workspace 22
Grace Hopper
Review
$75k
4,020
2,275
62
6295
Workspace 23
Blocked
$78k
4,140
2,350
69
6490
Workspace 24
Alan Turing
Queued
$81k
4,260
2,425
76
6685
Total691201562.594

Inline add, lazy loading and localization

Inline create rows, scroll-end lazy loading, skeleton/spinner/text loaders and localized labels are all prop-driven.

Project
Owner
Status
Budget
Revenue
Cost
Progress
Workspace 1
Ada Lovelace
Healthy
$12k
1,500
700
35
Workspace 2
Grace Hopper
Review
$15k
1,620
775
42
Workspace 3
Margaret Hamilton
Blocked
$18k
1,740
850
49
Workspace 4
Alan Turing
Queued
$21k
1,860
925
56
Workspace 5
Ada Lovelace
Healthy
$24k
1,980
1,000
63
Workspace 6
Grace Hopper
Review
$27k
2,100
1,075
70
Workspace 7
Margaret Hamilton
Blocked
$30k
2,220
1,150
77
Workspace 8
Alan Turing
Queued
$33k
2,340
1,225
84
Workspace 9
Ada Lovelace
Healthy
$36k
2,460
1,300
91
Workspace 10
Grace Hopper
Review
$39k
2,580
1,375
38
Cargando mas...

Column Definition API

DataTableColumnDef extends TanStack ColumnDef with field, headerName, type, align, flex, renderCell, renderHeader, description and filterOperators.

Full Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
$1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
$1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
$1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
$1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
$1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
$1,600
75
Jun 6, 2026
User 7
user7@example.com
Admin
$1,680
82
Jul 7, 2026
User 8
user8@example.com
Editor
$1,760
89
Aug 8, 2026
User 9
user9@example.com
Viewer
$1,840
96
Sep 9, 2026
User 10
user10@example.com
Admin
$1,920
43
Oct 10, 2026
User 11
user11@example.com
Editor
$2,000
50
Nov 11, 2026
User 12
user12@example.com
Viewer
$2,080
57
Dec 12, 2026

Tree data

Set treeData and provide getSubRows to render a parent/child hierarchy with automatic depth indentation. Expand All and Collapse All appear in the toolbar.

Name
Type
Members
Engineering
Department
42
Design
Department
14
Growth
Department
20

Column management

Resize columns by dragging the edge handle (double-click to auto-fit). Drag headers to reorder. Pin any column left or right via the ⋮ menu. Lock a column to prevent resize, reorder, and hide. Toggle visibility with the Columns button. Below: column groups created by nesting columns under a parent definition.

Resize: drag the ▕ handle at column edges. Double-click a handle to auto-fit. Reorder: drag column headers. Pin: open column ⋮ menu → Pin left / right. Lock: locked columns (currently: Name) cannot be resized, reordered, or hidden.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026
User 7
user7@example.com
Admin
1,680
82
Jul 7, 2026
User 8
user8@example.com
Editor
1,760
89
Aug 8, 2026

Column groups — nested columns under a shared header:

IdentityPerformance
Name
Role
Score
Revenue
Joined
User 1
Admin
40
1,200
Jan 1, 2026
User 2
Editor
47
1,280
Feb 2, 2026
User 3
Viewer
54
1,360
Mar 3, 2026
User 4
Admin
61
1,440
Apr 4, 2026
User 5
Editor
68
1,520
May 5, 2026
User 6
Viewer
75
1,600
Jun 6, 2026

Row management

Drag the ⠿ grip to reorder rows — the sorted array is emitted via onRowOrderChange. Pin rows to top or bottom via the grip menu. Use enableRowCopy / enableColumnCopy to add copy options in the row and column context menus.

Reorder rows: drag the ⠿ grip on the left. Pin rows: open the row grip menu → Pin top / bottom. Copy: use row ⋮ menu to copy a single row, or column ⋮ menu to copy all column values.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026
User 7
user7@example.com
Admin
1,680
82
Jul 7, 2026
User 8
user8@example.com
Editor
1,760
89
Aug 8, 2026

Row actions

rowActionMenu renders a ⋮ dropdown per row (supports separators, disabled/hidden guards, destructive variants). rowActionButtons renders inline buttons. bulkActions shows a panel when rows are selected. loadingRowIds dims individual rows during async mutations. onRowContextMenu / onCellContextMenu handle right-click events.

⋮ menu: per-row dropdown with Edit and Delete. Save button: inline button that triggers a 1.5 s loading state on that row. Bulk: select rows to show the bulk-action bar. Right-click any row or cell for a context menu.

Name
Email
Role
Revenue
Score
Joined
Actions
Actions
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026
User 7
user7@example.com
Admin
1,680
82
Jul 7, 2026
User 8
user8@example.com
Editor
1,760
89
Aug 8, 2026

Toolbar features

enableDensityToggle adds a Density menu (compact / standard / comfortable). enableExport adds a dropdown with CSV, JSON and XLSX. enableFullscreen expands the table to fill the viewport. onPrint adds a Print button. onRefresh adds a Refresh button. enableStatusBar pins a count bar below the table.

Density toggle · Export dropdown (CSV / JSON / XLSX) · Fullscreen · Print · Refresh — all in the toolbar. Status bar is pinned below.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026
User 7
user7@example.com
Admin
1,680
82
Jul 7, 2026
User 8
user8@example.com
Editor
1,760
89
Aug 8, 2026
User 9
user9@example.com
Viewer
1,840
96
Sep 9, 2026
User 10
user10@example.com
Admin
1,920
43
Oct 10, 2026
User 11
user11@example.com
Editor
2,000
50
Nov 11, 2026
User 12
user12@example.com
Viewer
2,080
57
Dec 12, 2026
12 rows

Sorting and filtering options

Hold Shift while clicking column headers to build a multi-column sort chain — numbered priority badges appear on each active sort icon. quickFilterColumns renders a search input below specified headers. enableFilterChips shows active filters as removable chips above the table.

Multi-sort: hold Shift and click column headers — numbered badges show sort priority. Quick filters: type in the input below each header. Filter chips: active filters appear as removable chips.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026
User 7
user7@example.com
Admin
1,680
82
Jul 7, 2026
User 8
user8@example.com
Editor
1,760
89
Aug 8, 2026
User 9
user9@example.com
Viewer
1,840
96
Sep 9, 2026
User 10
user10@example.com
Admin
1,920
43
Oct 10, 2026
User 11
user11@example.com
Editor
2,000
50
Nov 11, 2026
User 12
user12@example.com
Viewer
2,080
57
Dec 12, 2026

Pagination and status bar

The pagination bar includes a page-number dropdown, rows-per-page selector, total row count, and icon navigation. enableStatusBar adds a compact bar below showing total and selected row counts.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
12 rows
Page 1 of 3
12 rows

Row appearance

striped alternates row backgrounds. enableRowNumbers adds a fixed row-number column. getRowStatus colors the left border stripe per row. rowHeight sets a uniform or per-row pixel height. enableCellTooltip shows the raw value on hover. getCellClassName applies Tailwind classes to individual cells by value.

#
Name
Email
Role
Revenue
Score
Joined
1
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
2
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
3
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
4
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
5
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
6
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026
7
User 7
user7@example.com
Admin
1,680
82
Jul 7, 2026
8
User 8
user8@example.com
Editor
1,760
89
Aug 8, 2026
9
User 9
user9@example.com
Viewer
1,840
96
Sep 9, 2026
10
User 10
user10@example.com
Admin
1,920
43
Oct 10, 2026

Inline editing

Mark columns editable: true and provide valueSetter to write changes back. editMode controls whether a single click or double-click starts editing. enableUndoRedo adds Ctrl+Z / Ctrl+Y. enableValidation + displayValidate on column defs shows a red outline and error tooltip on invalid cells. dirtyRows tracks unsaved row IDs.

Double-click Name or Score to edit inline. Ctrl+Z / Ctrl+Y to undo/redo. Score must be 0–100 (red outline + tooltip on invalid). Dirty rows are tracked.

Name
Score
Role
Revenue
User 1
40
Admin
1,200
User 2
47
Editor
1,280
User 3
54
Viewer
1,360
User 4
61
Admin
1,440
User 5
68
Editor
1,520
User 6
75
Viewer
1,600
User 7
82
Admin
1,680
User 8
89
Editor
1,760

Clipboard and cell selection

enableCopyPaste lets users press Ctrl+C to copy selected rows as TSV — paste directly into Excel or Google Sheets. enablePaste enables Ctrl+V to paste TSV back into editable cells. enableCellSelection adds click-drag or Shift+click rectangular range selection.

Ctrl+C copies selected rows as TSV (paste into Excel / Sheets). Click-drag or Shift+click to select a cell range.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026
User 7
user7@example.com
Admin
1,680
82
Jul 7, 2026
User 8
user8@example.com
Editor
1,760
89
Aug 8, 2026

Conditional formatting

Set enableConditionalFormatting to add a Format button in the toolbar. Users open a drawer to create rules that highlight cells by column value — choose operator, value, background and text color. Rules are serializable and can be stored externally via conditionalFormattingRules + onConditionalFormattingRulesChange.

Name
Role
Score
Revenue
User 1
Admin
40
1,200
User 2
Editor
47
1,280
User 3
Viewer
54
1,360
User 4
Admin
61
1,440
User 5
Editor
68
1,520
User 6
Viewer
75
1,600
User 7
Admin
82
1,680
User 8
Editor
89
1,760
User 9
Viewer
96
1,840
User 10
Admin
43
1,920
User 11
Editor
50
2,000
User 12
Viewer
57
2,080

Built-in cell renderers and formatting

Set type on a column to get rich built-in cell rendering: badge (with badgeMap for color mapping), currency (Intl.NumberFormat), progress bar, star rating, link, avatar. Add locale / dateFormat / numberFormat / timezone per column for Intl-based formatting of date and number columns.

Name
Status
Revenue
Score
Rating
Joined
Alice
Active
$1,200.00
20%
January 1, 2022
Bob
Paused
$1,540.00
30%
February 4, 2022
Carol
Blocked
$1,880.00
40%
March 7, 2022
Dave
Invited
$2,220.00
50%
April 10, 2022
Eve
Active
$2,560.00
60%
May 13, 2022
Frank
Paused
$2,900.00
70%
June 16, 2022
Grace
Blocked
$3,240.00
80%
July 19, 2022
Heidi
Invited
$3,580.00
90%
August 22, 2022

Analytics features

enableToolPanel adds a collapsible right-side panel with Columns, Filters, and Stats tabs. enableHeaderStats pins an aggregated stats row below column headers (count / sum / avg / min / max / unique — configurable per column via headerStatsConfig). enableSavedViews adds a drawer to save, load, update and delete named table states.

Tool panel: open the ▶ button on the right to access Columns, Filters, and Stats tabs. Saved views: toolbar button to save and restore named table states. Header stats: sum/avg/count row pinned below column headers.

Name
Email
Role
Revenue
Score
Joined
count12
count12
count12
count12
sum19,680
avg63.5
count12
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026
User 7
user7@example.com
Admin
1,680
82
Jul 7, 2026
User 8
user8@example.com
Editor
1,760
89
Aug 8, 2026
User 9
user9@example.com
Viewer
1,840
96
Sep 9, 2026
User 10
user10@example.com
Admin
1,920
43
Oct 10, 2026
User 11
user11@example.com
Editor
2,000
50
Nov 11, 2026
User 12
user12@example.com
Viewer
2,080
57
Dec 12, 2026

Live data

Set enableLiveData to watch for data prop changes and flash updated cells with a highlight animation. Pair with liveDataKey (default: "id") as the row identity key. Useful for dashboards with WebSocket or polling data sources.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026

Async detail panel

loadDetailPanel receives a Row and returns a Promise<ReactNode>. The resolved content is displayed in an expandable panel below the row. Panels are LRU-cached (detailPanelCacheSize, default 20) so re-expanding does not re-fetch.

Click ▶ to expand a row — panel loads async then caches.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
User 6
user6@example.com
Viewer
1,600
75
Jun 6, 2026

Pivot mode

Set enablePivot to add a Pivot toolbar button. Clicking it opens a configuration drawer where you choose the row group field, pivot field, value field and aggregation function. The table re-renders as a cross-tabulation view. Pass pivotConfig + onPivotConfigChange for controlled state.

30 rows across 4 regions, 3 products, 3 categories and 4 quarters. Click the Pivot button in the toolbar to open the configuration drawer and choose row group, pivot field, value field and aggregation.

Region
Product
Category
Quarter
Rep
Sales
Cost
Units
Margin %
North
Widget A
Hardware
Q1
Alice
12,400
7,200
80
42
North
Widget B
Software
Q1
Bob
8,800
2,900
55
67
North
Widget C
Services
Q1
Carol
6,100
4,200
31
31
South
Widget A
Hardware
Q1
Dave
9,500
5,600
63
41
South
Widget B
Software
Q1
Eve
11,200
3,700
70
67
East
Widget A
Hardware
Q1
Frank
7,800
4,500
52
42
East
Widget C
Services
Q1
Grace
5,200
3,600
26
31
West
Widget B
Software
Q1
Hank
9,900
3,200
62
68
West
Widget A
Hardware
Q1
Ivy
14,100
8,200
94
42
North
Widget B
Software
Q2
Alice
13,000
4,300
82
67
North
Widget A
Hardware
Q2
Bob
15,500
9,100
103
41
South
Widget C
Services
Q2
Carol
7,300
5,000
37
32
South
Widget A
Hardware
Q2
Dave
10,800
6,300
72
42
East
Widget B
Software
Q2
Eve
6,200
2,100
39
66
East
Widget A
Hardware
Q2
Frank
13,500
7,900
90
41
30 rows
Page 1 of 2

State persistence

Pass a unique stateKey to automatically save and restore sort, filter, column visibility, column sizing, column order, pagination and density to localStorage. Refresh the page — the table state is fully restored.

Sort, filter, resize, and paginate — then refresh the page. State is restored from localStorage automatically.

Name
Email
Role
Revenue
Score
Joined
User 1
user1@example.com
Admin
1,200
40
Jan 1, 2026
User 2
user2@example.com
Editor
1,280
47
Feb 2, 2026
User 3
user3@example.com
Viewer
1,360
54
Mar 3, 2026
User 4
user4@example.com
Admin
1,440
61
Apr 4, 2026
User 5
user5@example.com
Editor
1,520
68
May 5, 2026
12 rows
Page 1 of 3

Mobile card view

Set mobileBreakpoint to "sm", "md", or "lg". Below that breakpoint the table switches to a label/value card list — one card per row, one item per column. Resize the browser window to see the transition.

Resize the browser to below the md breakpoint to see the card view.

NameUser 1
Emailuser1@example.com
RoleAdmin
Revenue1,200
Score40
JoinedJan 1, 2026
NameUser 2
Emailuser2@example.com
RoleEditor
Revenue1,280
Score47
JoinedFeb 2, 2026
NameUser 3
Emailuser3@example.com
RoleViewer
Revenue1,360
Score54
JoinedMar 3, 2026
NameUser 4
Emailuser4@example.com
RoleAdmin
Revenue1,440
Score61
JoinedApr 4, 2026
NameUser 5
Emailuser5@example.com
RoleEditor
Revenue1,520
Score68
JoinedMay 5, 2026
NameUser 6
Emailuser6@example.com
RoleViewer
Revenue1,600
Score75
JoinedJun 6, 2026

Custom empty states

NoRowsOverlay renders when the data source is empty. NoResultsOverlay renders when filters/search produce zero matches from a non-empty dataset. Both accept any ReactNode — render illustrations, calls to action, or upload prompts.

Name
Email
Role
Revenue
Score
Joined

No users yet. Create the first one.

Features

  • Rich DataTableColumnDef API — field, type, align, flex, renderCell, description, filterOperators.
  • Tree data with depth indentation and Expand All / Collapse All toolbar buttons.
  • Ctrl+C copy/paste to TSV for Excel and Google Sheets.
  • Density toggle — compact, standard, comfortable cell padding.
  • Bulk actions panel when rows are selected; row action menu and inline button columns.
  • Pagination with page-number dropdown, rows-per-page selector and total row count.
  • Row copy and column copy via row/column menus.
  • Full slot system — replace toolbar, pagination, column menu, filter, search, loaders, empty states.
  • Distinct empty states: NoRowsOverlay (empty source) vs NoResultsOverlay (filtered empty).
  • Sorting, global search, nested AND/OR filters, selection, resizing, pinning and reordering.
  • Virtualized rows and columns for large datasets with lazy loading.
  • Column configuration, aggregation totals, inline create, detail panels and localization.
  • Server-side state adapter, skeleton/spinner/text loaders and accessibility built in.

Installation

bash
pnpm dlx structyl add data-table

API Reference

DataTable

A typed, batteries-included data grid with MUI-like feature coverage on top of TanStack Table.

PropTypeDefault
columnsDataTableColumn<TData>[]

Column definitions for the dataset.

dataTData[]

Rows to render.

virtualboolean | { estimatedRowHeight?: number; overscan?: number }

Render rows with virtualization.

virtualColumnsboolean | { estimatedColumnWidth?: number; overscan?: number }

Render visible leaf columns with horizontal virtualization for wide grids.

enableSortingboolean

Enable sortable column headers.

true
enableFilteringboolean

Enable column filtering state.

false
enableAdvancedFilteringboolean

Render the nested AND/OR filter builder.

false
enableGlobalSearchboolean

Render a global quick-search input.

false
enableRowSelectionboolean | 'single'

Enable row selection checkboxes.

false
enableColumnSelectionboolean

Track selected columns from the column menu/configuration panel.

false
enablePaginationboolean

Render pagination controls.

false
enableExpandingboolean

Enable expandable rows or tree rows when sub-rows are provided.

false
enableGroupingboolean

Enable row grouping from column menus.

false
enableColumnResizingboolean

Allow resizing columns.

false
enableColumnReorderingboolean

Allow reordering columns.

false
enableRowReorderingboolean

Allow drag-and-drop row reordering.

false
enableColumnPinningboolean

Allow pinning columns.

false
enableRowPinningboolean

Allow rows to be pinned to top or bottom.

false
enableColumnConfigurationboolean

Render the column visibility/configuration panel.

false
pageSizenumber

Initial rows per page.

10
loadingboolean

Show the loading state.

loadingMoreboolean

Show a lazy-loading row at the bottom.

loadingVariant'text' | 'skeleton' | 'spinner'

Choose text, skeleton, or spinner loading UI.

'text'
skeletonRowsnumber

Rows to render for the skeleton loading state.

5
errorReactNode

Render an error state.

emptyStateReactNode

Render custom empty content.

globalFilterstring

Controlled global search value.

defaultGlobalFilterstring

Uncontrolled initial global search value.

onGlobalFilterChange(value: string) => void

Called when the global search changes.

advancedFilterDataTableFilterGroup

Controlled nested filter model.

defaultAdvancedFilterDataTableFilterGroup

Uncontrolled initial nested filter model.

onAdvancedFilterChange(filter?: DataTableFilterGroup) => void

Called when the filter builder changes.

rowActions(row: Row<TData>) => ReactNode

Adds an actions column at the end of the grid.

inlineCreateRowDataTableInlineCreate

Renders inline add-row fields above the data rows.

aggregationsRecord<string, 'sum' | 'avg' | 'min' | 'max' | 'count' | fn>

Column aggregation functions for footer totals.

rowTotalsboolean | DataTableRowTotals<TData>

Adds a row total column calculated from selected columns.

rowPinningDataTableRowPinningState

Controlled top/bottom row pinning state.

renderDetailPanel(row: Row<TData>) => ReactNode

Renders a master/detail panel below expanded rows.

getCellColSpan(cell, row) => number | undefined

Returns a cell column span.

getCellRowSpan(cell, row) => number | undefined

Returns a cell row span.

getRowClassName(row) => string | undefined

Adds row-level classes for row configuration.

getRowStyle(row) => CSSProperties | undefined

Adds row-level inline styles.

getRowHeight(row) => number | undefined

Custom row height, used by row virtualization.

heightnumber | string

Fixed grid body height.

maxHeightnumber | string

Maximum grid body height.

fullHeightboolean

Fill the parent height.

autoHeightboolean

Let content determine the body height.

onLoadMore() => void

Called near the bottom for lazy loading.

hasMoreboolean

Whether lazy loading can request more rows.

onRowOrderChange(rows, rowIds) => void

Called after drag-and-drop row reorder.

onColumnOrderChange(columnIds) => void

Called after drag-and-drop column reorder.

localeTextPartial<DataTableLocaleText>

Localizes built-in labels, buttons, and state text.

serverSide{ state; onStateChange; rowCount }

External state adapter for remote data.

tableRefMutableRefObject<Table<TData> | null>

Imperative access to the TanStack Table instance.

classNamestring

Additional Tailwind classes, merged with the component defaults.

DataTableToolbar

Optional toolbar for search and actions.

PropTypeDefault
tableTable<TData>

TanStack Table instance.

DataTableAdvancedFilter

Nested AND/OR filter builder.

PropTypeDefault
tableTable<TData>

TanStack Table instance.

DataTableColumnConfiguration

Column visibility, pinning, grouping, and selection menu.

PropTypeDefault
tableTable<TData>

TanStack Table instance.

DataTableColumnVisibility

Column visibility menu alias.

PropTypeDefault
tableTable<TData>

TanStack Table instance.

Data Table | structyl