Skip to content

Data Table

A table with sortable columns and a text filter for client-side data.

  • Static data with no sorting: use Table.
  • Thousands of rows: sort and filter on the server and pass the page of rows.

Install

Terminal
pnpm dlx shadcn@latest add @acme/data-table

Or import from the package: import { DataTable } from '@acme/react'

Examples

Table basic

5 of 5 rows

Invoices
INV-1042Northwind TradersPaid$1,250.00
INV-1043Contoso LtdOverdue$860.00
INV-1044FabrikamDraft$4,300.00
INV-1045Adventure WorksPaid$2,175.00
INV-1046Tailspin ToysOverdue$540.00
data-table-basic.tsx
'use client'

import { Badge } from '@/components/ui/badge'
import { DataTable, type DataTableColumn } from '@/components/ui/data-table'

type Invoice = {
  id: string
  customer: string
  status: 'Paid' | 'Overdue' | 'Draft'
  amount: number
}

const invoices: Invoice[] = [
  { id: 'INV-1042', customer: 'Northwind Traders', status: 'Paid', amount: 1250 },
  { id: 'INV-1043', customer: 'Contoso Ltd', status: 'Overdue', amount: 860 },
  { id: 'INV-1044', customer: 'Fabrikam', status: 'Draft', amount: 4300 },
  { id: 'INV-1045', customer: 'Adventure Works', status: 'Paid', amount: 2175 },
  { id: 'INV-1046', customer: 'Tailspin Toys', status: 'Overdue', amount: 540 },
]

const STATUS = { Paid: 'success', Overdue: 'destructive', Draft: 'secondary' } as const
const usd = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })

const columns: DataTableColumn<Invoice>[] = [
  { key: 'id', header: 'Invoice', sortable: true },
  { key: 'customer', header: 'Customer', sortable: true },
  {
    key: 'status',
    header: 'Status',
    sortable: true,
    cell: (r) => <Badge variant={STATUS[r.status]}>{r.status}</Badge>,
  },
  {
    key: 'amount',
    header: 'Amount',
    sortable: true,
    align: 'end',
    cell: (r) => usd.format(r.amount),
  },
]

export default function DataTableBasic() {
  return (
    <DataTable
      caption="Invoices"
      columns={columns}
      data={invoices}
      rowKey="id"
      filterKeys={['id', 'customer', 'status']}
    />
  )
}

Props

Data Table props
PropTypeDefaultDescription
caption (required)string—Names the table and its filter.
columns (required)DataTableColumn<T>[]—key, header, cell, sortable, align.
data (required)T[]—Rows.
rowKey (required)keyof T—Unique row key.
rowHeaderkeyof Tfirst columnColumn used as row headers.
filterKeys(keyof T)[]—Columns the text filter searches.
emptyMessagestring'No matching rows.'Shown when nothing matches.

Accessibility

Keyboard
KeyAction
TabMoves to sort buttons and the filter
Enter / SpaceToggles sort: ascending, descending, none
Role
table with sortable column headers
You provide
  • A caption.
Built in
  • Sort state uses aria-sort on the header cell.
  • The row count and sort order are announced in a status region after each change.
WCAG 2.2 criteria
1.3.1, 2.1.1, 4.1.3

Don’t

  • Sort columns that have no meaningful order.

Tokens

  • color.border
  • color.muted-foreground
  • color.foreground