Skip to Content
Documentation
Getting startedComponentsChartsTheming
Get Pro
Overview
Concepts

Data Table

Used to display large datasets with sorting and pagination

Source

Arcwell Health

arcwell.test

Enterprise

Active

$9,800

Mar 18, 2026

Priya Shah

Bower Supply

bowersupply.test

Starter

Trial

$720

Nov 18, 2026

Priya Shah

Copperline

copperline.test

Growth

Active

$4,700

May 18, 2026

Maya Chen

Daybreak Energy

daybreak.test

Enterprise

Active

$15,100

Jun 18, 2026

Noah Williams

Fieldnote Studio

fieldnote.test

Starter

Paused

$890

Apr 18, 2026

Jon Bell

Goodweather

goodweather.test

Growth

Active

$5,400

Dec 18, 2026

Jon Bell

Kite & Harbor

kiteharbor.test

Growth

Trial

$3,200

Feb 18, 2026

Noah Williams

Morrow Works

morrow.test

Growth

Paused

$2,800

Sep 18, 2026

Maya Chen

1–8 of 12

Usage

The DataTable is built on TanStack Table v9. The useDataTable hook creates a table instance with all parts, cell components and header components bound to it, so you never import the parts separately.

import {
  createDataTableColumnHelper,
  useDataTable,
} from '#components/ui/data-table'

Define your columns with createDataTableColumnHelper. The cell components are bound to the column definition, which keeps the cells typed and lets them read the value from the table context.

const columnHelper = createDataTableColumnHelper<Account>()

const columns = columnHelper.columns([
  columnHelper.accessor('company', {
    header: 'Account',
    cell: ({ cell }) => <cell.TextCell />,
  }),
  columnHelper.accessor('mrr', {
    header: 'MRR',
    cell: ({ cell }) => <cell.NumberCell style="currency" currency="USD" />,
  }),
  columnHelper.accessor('renewal', {
    header: 'Renewal',
    cell: ({ cell }) => <cell.DateCell month="short" day="numeric" />,
  }),
])

Then compose the parts. table.Table renders the header and body for you, wrap it in table.ScrollArea to make it scrollable.

const table = useDataTable({ columns, data })

return (
  <table.Provider>
    <table.Root>
      <table.ScrollArea>
        <table.Table aria-label="Accounts" />
      </table.ScrollArea>
      <table.Pagination />
    </table.Root>
  </table.Provider>
)

Compose the header and body explicitly when you need to customize them.

<table.Table aria-label="Accounts">
  <table.Header />
  <table.Body />
</table.Table>
info
useDataTable accepts all TanStack Table options, like enableRowSelection, getSubRows, initialState and state with on[Feature]Change handlers for controlled state. Sorting, global and column filtering, pagination, row selection, column visibility, column pinning and column resizing are enabled out of the box.

Examples

Striped

Use the striped prop to add zebra-stripes to the rows, the size prop to change the density of the table, and the variant prop to switch between the line and outline appearance.

Northstar Labs

Enterprise

Active

$12,400

Maya Chen

Kite & Harbor

Growth

Trial

$3,200

Noah Williams

Arcwell Health

Enterprise

Active

$9,800

Priya Shah

Fieldnote Studio

Starter

Paused

$890

Jon Bell

Copperline

Growth

Active

$4,700

Maya Chen

Daybreak Energy

Enterprise

Active

$15,100

Noah Williams

Plainspoken

Starter

Trial

$640

Priya Shah

Orbit Commerce

Growth

Active

$6,250

Jon Bell

Morrow Works

Growth

Paused

$2,800

Maya Chen

Tandem Security

Enterprise

Active

$17,600

Noah Williams

Interactive Rows

Use the onRowClick prop on table.Body to make rows clickable. Rows become keyboard-interactive as well.

Northstar Labs

northstar.test

Enterprise

Active

$12,400

Maya Chen

Kite & Harbor

kiteharbor.test

Growth

Trial

$3,200

Noah Williams

Arcwell Health

arcwell.test

Enterprise

Active

$9,800

Priya Shah

Fieldnote Studio

fieldnote.test

Starter

Paused

$890

Jon Bell

Copperline

copperline.test

Growth

Active

$4,700

Maya Chen

Daybreak Energy

daybreak.test

Enterprise

Active

$15,100

Noah Williams

Plainspoken

plainspoken.test

Starter

Trial

$640

Priya Shah

Orbit Commerce

orbitcommerce.test

Growth

Active

$6,250

Jon Bell

1–8 of 12

Composable Rows

Pass a render function to table.Body to render your own rows. The body keeps owning the loop, empty state and virtualization, spread the rowProps argument into table.Row to keep the layout intact.

Northstar Labs

Enterprise

Active

$12,400

Maya Chen

Kite & Harbor

Growth

Trial

$3,200

Noah Williams

Arcwell Health

Enterprise

Active

$9,800

Priya Shah

Fieldnote Studio

Starter

Paused

$890

Jon Bell

Copperline

Growth

Active

$4,700

Maya Chen

Daybreak Energy

Enterprise

Active

$15,100

Noah Williams

Plainspoken

Starter

Trial

$640

Priya Shah

Orbit Commerce

Growth

Active

$6,250

Jon Bell

Morrow Works

Growth

Paused

$2,800

Maya Chen

Tandem Security

Enterprise

Active

$17,600

Noah Williams

Context Menu

The row render function also lets you wrap rows in other components, like a context menu.

Pinned Columns

Use the columnPinning state to pin columns to the start or end of the table. Pinned columns stay in place while the table scrolls horizontally.

Northstar Labs

northstar.test

Enterprise

Active

$12,400

Jan 18, 2026

Maya Chen

Kite & Harbor

kiteharbor.test

Growth

Trial

$3,200

Feb 18, 2026

Noah Williams

Arcwell Health

arcwell.test

Enterprise

Active

$9,800

Mar 18, 2026

Priya Shah

Fieldnote Studio

fieldnote.test

Starter

Paused

$890

Apr 18, 2026

Jon Bell

Copperline

copperline.test

Growth

Active

$4,700

May 18, 2026

Maya Chen

Daybreak Energy

daybreak.test

Enterprise

Active

$15,100

Jun 18, 2026

Noah Williams

Plainspoken

plainspoken.test

Starter

Trial

$640

Jul 18, 2026

Priya Shah

Orbit Commerce

orbitcommerce.test

Growth

Active

$6,250

Aug 18, 2026

Jon Bell

Morrow Works

morrow.test

Growth

Paused

$2,800

Sep 18, 2026

Maya Chen

Tandem Security

tandemsecurity.test

Enterprise

Active

$17,600

Oct 18, 2026

Noah Williams

Pagination

Render table.Pagination to add pagination controls. It shows the row range and previous/next navigation by default.

Arcwell Health

arcwellhealth.test

Starter

Paused

$1,074

Mar 18, 2026

Priya Shah

Arcwell Health 10

arcwellhealth.test

Starter

Paused

$8,472

Sep 18, 2026

Maya Chen

Arcwell Health 11

arcwellhealth.test

Starter

Paused

$9,294

Mar 18, 2026

Priya Shah

Arcwell Health 12

arcwellhealth.test

Starter

Paused

$10,116

Sep 18, 2026

Maya Chen

Arcwell Health 13

arcwellhealth.test

Starter

Paused

$10,938

Mar 18, 2026

Priya Shah

Arcwell Health 14

arcwellhealth.test

Starter

Paused

$11,760

Sep 18, 2026

Maya Chen

Arcwell Health 15

arcwellhealth.test

Starter

Paused

$12,582

Mar 18, 2026

Priya Shah

Arcwell Health 2

arcwellhealth.test

Starter

Paused

$1,896

Sep 18, 2026

Maya Chen

Arcwell Health 3

arcwellhealth.test

Starter

Paused

$2,718

Mar 18, 2026

Priya Shah

Arcwell Health 4

arcwellhealth.test

Starter

Paused

$3,540

Sep 18, 2026

Maya Chen

Arcwell Health 5

arcwellhealth.test

Starter

Paused

$4,362

Mar 18, 2026

Priya Shah

Arcwell Health 6

arcwellhealth.test

Starter

Paused

$5,184

Sep 18, 2026

Maya Chen

Arcwell Health 7

arcwellhealth.test

Starter

Paused

$6,006

Mar 18, 2026

Priya Shah

Arcwell Health 8

arcwellhealth.test

Starter

Paused

$6,828

Sep 18, 2026

Maya Chen

Arcwell Health 9

arcwellhealth.test

Starter

Paused

$7,650

Mar 18, 2026

Priya Shah

1–15 of 90

Numbered Pagination

Compose table.Pagination with table.PaginationRange and table.PaginationPages to show numbered page buttons.

Arcwell Health

arcwellhealth.test

Starter

Paused

$1,074

Priya Shah

Arcwell Health 10

arcwellhealth.test

Starter

Paused

$8,472

Maya Chen

Arcwell Health 11

arcwellhealth.test

Starter

Paused

$9,294

Priya Shah

Arcwell Health 12

arcwellhealth.test

Starter

Paused

$10,116

Maya Chen

Arcwell Health 13

arcwellhealth.test

Starter

Paused

$10,938

Priya Shah

Arcwell Health 14

arcwellhealth.test

Starter

Paused

$11,760

Maya Chen

Arcwell Health 15

arcwellhealth.test

Starter

Paused

$12,582

Priya Shah

Arcwell Health 2

arcwellhealth.test

Starter

Paused

$1,896

Maya Chen

Arcwell Health 3

arcwellhealth.test

Starter

Paused

$2,718

Priya Shah

Arcwell Health 4

arcwellhealth.test

Starter

Paused

$3,540

Maya Chen

1–10 of 90

Page Select

Use table.PageSelect to let users jump to a page with a select, useful for tables with many pages.

Arcwell Health

arcwellhealth.test

Starter

Paused

$1,074

Priya Shah

Arcwell Health 10

arcwellhealth.test

Starter

Paused

$8,472

Maya Chen

Arcwell Health 11

arcwellhealth.test

Starter

Paused

$9,294

Priya Shah

Arcwell Health 12

arcwellhealth.test

Starter

Paused

$10,116

Maya Chen

Arcwell Health 13

arcwellhealth.test

Starter

Paused

$10,938

Priya Shah

Arcwell Health 14

arcwellhealth.test

Starter

Paused

$11,760

Maya Chen

Arcwell Health 15

arcwellhealth.test

Starter

Paused

$12,582

Priya Shah

Arcwell Health 2

arcwellhealth.test

Starter

Paused

$1,896

Maya Chen

Arcwell Health 3

arcwellhealth.test

Starter

Paused

$2,718

Priya Shah

Arcwell Health 4

arcwellhealth.test

Starter

Paused

$3,540

Maya Chen

1–10 of 90

Page

Manual Pagination

Set manualPagination and rowCount to paginate on the server. The table leaves the row model alone and calls onPaginationChange when the page changes.

Loading…
1–10 of 90

Define a footer on a column to render a sticky footer row, for example page totals. The footer only renders when at least one column defines one; pass sticky={false} to let it scroll with the rows.

Arcwell Health

Enterprise

$9,800

Bower Supply

Starter

$720

Copperline

Growth

$4,700

Daybreak Energy

Enterprise

$15,100

Fieldnote Studio

Starter

$890

Goodweather

Growth

$5,400

Kite & Harbor

Growth

$3,200

Morrow Works

Growth

$2,800

Page total

$42,610

1–8 of 12

Empty State

Pass emptyState to table.Body to render custom content when there are no rows. The built-in table.NoResults reflects the active filters in its message and clears them on click — pass onReset when filters are managed outside the table.

No accounts found for "wayfarer"

Sub Rows

Use getSubRows to render hierarchical data. Add an ExpanderCell to a column to toggle the child rows.

Northstar Labs

Active

$800

Maya Chen

Kite & Harbor

Trial

$2,170

Noah Williams

Arcwell Health

Paused

$3,540

Priya Shah

Fieldnote Studio

Active

$4,910

Jon Bell

Copperline

Trial

$6,280

Maya Chen

Daybreak Energy

Paused

$7,650

Noah Williams

Orbit Commerce

Active

$9,020

Priya Shah

Tandem Security

Trial

$10,390

Jon Bell

Grouped Rows

Use the grouping state to group rows by a column, and set aggregationFn on the other columns to aggregate their values.

Enterprise

(4)

$27,860

Northstar Labs

Active

$800

Fieldnote Studio

Active

$4,910

Orbit Commerce

Active

$9,020

Lattice Grove

Active

$13,130

Growth

(4)

$33,340

Kite & Harbor

Trial

$2,170

Copperline

Trial

$6,280

Tandem Security

Trial

$10,390

Signal House

Trial

$14,500

Starter

(4)

$38,820

Arcwell Health

Paused

$3,540

Daybreak Energy

Paused

$7,650

Goodweather

Paused

$11,760

Sable Finance

Paused

$15,870

Expanded Row

Use getRowCanExpand together with the renderExpandedRow prop on table.Body to render a full width panel below a row.

Northstar Labs

Enterprise

Active

$800

Kite & Harbor

Growth

Trial

$2,170

Arcwell Health

Starter

Paused

$3,540

Fieldnote Studio

Enterprise

Active

$4,910

Copperline

Growth

Trial

$6,280

Daybreak Energy

Starter

Paused

$7,650

Orbit Commerce

Enterprise

Active

$9,020

Tandem Security

Growth

Trial

$10,390

Cell Selection

Set enableCellSelection to enable spreadsheet-style cell selection. Cells can be selected by dragging, or by holding Shift and Cmd to select ranges.

Northstar Labs

northstarlabs.test

Enterprise

Active

$800

Jan 18, 2026

Maya Chen

Kite & Harbor

kiteharbor.test

Growth

Trial

$2,170

Feb 18, 2026

Noah Williams

Arcwell Health

arcwellhealth.test

Starter

Paused

$3,540

Mar 18, 2026

Priya Shah

Fieldnote Studio

fieldnotestudio.test

Enterprise

Active

$4,910

Apr 18, 2026

Jon Bell

Copperline

copperline.test

Growth

Trial

$6,280

May 18, 2026

Maya Chen

Daybreak Energy

daybreakenergy.test

Starter

Paused

$7,650

Jun 18, 2026

Noah Williams

Orbit Commerce

orbitcommerce.test

Enterprise

Active

$9,020

Jul 18, 2026

Priya Shah

Tandem Security

tandemsecurity.test

Growth

Trial

$10,390

Aug 18, 2026

Jon Bell

Goodweather

goodweather.test

Starter

Paused

$11,760

Sep 18, 2026

Maya Chen

Lattice Grove

latticegrove.test

Enterprise

Active

$13,130

Oct 18, 2026

Noah Williams

0 cells selected

Virtual Rows

Wrap table.Table in table.Virtualizer to only render the rows in view. This lets you render tens of thousands of rows without paginating.

warning
Virtualization requires a table.ScrollArea with a fixed height, and can't be combined with renderExpandedRow.

Virtual Grid

Pass the columns prop to table.Virtualizer to window the columns as well. Pinned columns are always rendered.

Props

Root

PropDefaultType
variant 'line'
'line' | 'outline'

The visual style of the table.

size 'md'
'sm' | 'md' | 'lg'

The size of the table.

layout 'grow'
'grow' | 'fixed'

`grow` stretches columns to fill the available width, `fixed` keeps columns at their configured sizes. Column virtualization always behaves as `fixed`.

striped false
boolean

Whether to add zebra-stripes to the rows.

stickyHeader true
boolean

Keeps the header visible while the body scrolls.

Body

PropDefaultType
children
(row: Row<TData>, rowProps: DataTableRowRenderProps) => React.ReactNode

Custom row renderer. The body keeps owning the loop, empty state and virtualization, the callback only decides what each row looks like. Spread `rowProps` into `table.Row`.

onRowClick
(row: Row<TData>, event: React.MouseEvent | React.KeyboardEvent) => void

Rows become clickable and keyboard-interactive when set. Applies to the default row rendering, custom `children` handle their own interaction.

renderExpandedRow
(row: Row<TData>) => React.ReactNode

Renders an extra full-width row below rows where `getIsExpanded()` is true. Not supported in combination with row virtualization.

emptyState
React.ReactNode

Rendered when the row model is empty.

PropDefaultType
sticky true
boolean

Keeps the footer visible while the body scrolls.

Virtualizer

PropDefaultType
children *
React.ReactNode

The `table.Table` part to virtualize.

rows true
boolean

Whether to virtualize the rows (vertical).

columns false
boolean

Whether to virtualize the center (unpinned) columns (horizontal). Pinned columns always render.

rowOptions
Partial<VirtualizerOptions<HTMLDivElement, HTMLTableRowElement>>

Options passed to the row virtualizer, for example `overscan` or `estimateSize`.

columnOptions
Partial<VirtualizerOptions<HTMLDivElement, HTMLTableCellElement>>

Options passed to the column virtualizer.

Previous

Data List

Next

Dialog