AG Design System

Component

Table

The default table for AG. A fully-featured table powered by TanStack Table v8 with sorting, search, pagination, row selection, column visibility, and type-aware per-column filters, all styled with AG tokens.

Installation

Install from the live registry into any shadcn-initialized app (another project). Prefer installing ag-globals first so AG tokens and fonts are present.

npx shadcn@latest add https://design.ag.org/r/table

Usage

Use Table for any tabular data. Enable only the interactions you need (sort, filter, paginate, select) and turn the rest off for simple, read-only tables.

Composition

Playground

Preview
INV-001Acme CorpPaid$250.001/12/2024
INV-002GlobexPending$1200.003/4/2024
INV-003InitechPaid$820.005/21/2024
INV-004UmbrellaOverdue$430.007/9/2024
6 rows

Configure

Yes

Demo the per-column filters (text, select, range, date-range).

No

Show a search input in the toolbar.

Yes

Show pagination controls below the table.

No

Prepend a checkbox column for row selection.

No

Show a dropdown to toggle column visibility.

Code

import { DataTable, type ColumnDef } from "@/components/ui/data-table"
// Declare a per-column filter by setting meta.filterVariant on the column def.
type Invoice = {
  invoice: string
  customer: string
  status: string
  amount: number
  joined: Date
}

const columns: ColumnDef<Invoice>[] = [
  { accessorKey: "invoice", header: "Invoice" },
  { accessorKey: "customer", header: "Customer", meta: { filterVariant: "text" } },
  { accessorKey: "status", header: "Status", meta: { filterVariant: "select" } },
  {
    accessorKey: "amount",
    header: "Amount",
    cell: (info) => `$${(info.getValue() as number).toFixed(2)}`,
    meta: { filterVariant: "range" },
  },
  {
    accessorKey: "joined",
    header: "Joined",
    cell: (info) => (info.getValue() as Date).toLocaleDateString(),
    meta: { filterVariant: "date-range" },
  },
]

const data: Invoice[] = [
  { invoice: "INV-001", customer: "Acme Corp", status: "Paid", amount: 250, joined: new Date("2024-01-12") },
  { invoice: "INV-002", customer: "Globex", status: "Pending", amount: 1200, joined: new Date("2024-03-04") },
  { invoice: "INV-003", customer: "Initech", status: "Paid", amount: 820, joined: new Date("2024-05-21") },
]

<DataTable columns={columns} data={data} pagination />

Variants & States

Supported variants, sizes, and interaction states for this component.

Configurations

  • With title
  • With footer

Props

PropTypeDefault valueDescription
columnsColumnDef<TData>[], Column definitions. Use createColumnHelper<TData>() for full type inference.
dataTData[], Array of row objects to render.
searchableboolean | stringfalsetrue enables a global filter; a column id filters that single column.
paginationbooleanfalseShow pagination controls.
pageSizenumber10Rows per page when pagination is enabled.
selectablebooleanfalsePrepend a per-row selection checkbox column.
onSelectionChange(selected: TData[]) => void, Fires with the selected row objects whenever selection changes.
columnVisibilitybooleanfalseShow a column visibility toggle dropdown.
column.meta.filterVariant"text" | "select" | "multi-select" | "range" | "date-range", Set on a column def to render a type-appropriate filter control in the toolbar. Omit for no per-column filter.
column.meta.filterLabelstring, Optional human label for a column's filter control (defaults to the column header/id).

Do

  • Define columns with createColumnHelper for full type safety
  • Declare meta.filterVariant per column to give each filter the right control
  • Enable pagination for large datasets rather than rendering every row
  • Provide a meaningful title so the table has an accessible caption

Don't

  • Don't enable heavy features (filters, pagination) for a handful of static rows
  • Don't hide the search input when there are many rows
  • Don't use a range filter on non-numeric columns, use select instead
  • Don't put unrelated data in a single table, split into multiple tables