Data table

Rows returned by a query, with sortable columns and a CSV download.

Loading preview…

Install

  1. 1

    Run this command in your Tailwind CSS project. It adds components/ai/data-table.tsx and installs its dependencies.

    $ npx shadcn@latest add https://gradientdeck.com/ai-components/r/data-table.json

Usage & API

Example

data-table.tsx
import { DataTable } from "@/components/ai/data-table"

<DataTable
  title="…"
  columns={[]}
  rows={[]}
  sort={null}
  onSortChange={() => {}}
/>

Props DataTable

PropType & descriptionRequired
titlestringRequired
metastringOptional
columnsColumn<Row>[]Required
rowsRow[]Required
sort{ key: keyof Row & string; dir: "asc" | "desc" } | nullRequired
onSortChange(sort: { key: keyof Row & string; dir: "asc" | "desc" } | null) => voidRequired
filenamestringOptional

Dependencies

  • React
  • Tailwind CSS
  • motion
  • lucide-react
Implementation notes

Result table is the only variant. The sample title is Top accounts by MRR and the meta is 7 rows · from billing.subscriptions · 0.04s. Columns are Account, Plan, Seats, MRR and 30d. Seats, MRR and 30d are numeric. MRR formats with a dollar sign and grouping. 30d formats as a signed percent to one decimal, green above zero and red below. The seven accounts are Halden Logistics, Marrow & Finch, Oakline Clinics, Pinewood Studio, Tessel Robotics, Brightwater Co-op and Northgate Legal, across Team, Business and Enterprise. The sample opens sorted by MRR descending, so Tessel Robotics at $21,700 leads and Pinewood at $490 is last. The file saved by the button is top-accounts.csv, and it follows that sort until the person changes it. A third click on MRR clears the sort and the CSV then follows the original array.

Choosing a layout

Use it when the model answered with a set of records and the person will sort them and maybe take them away. Accounts, invoices, search hits with a few fields, or the output of a query the agent ran all fit, as long as you have already parsed them into rows. Put the query, the row count and the timing in the meta string if you have them. Do not ask the table to format a value that should also affect order. Format for the eye, and keep the sortable value numeric or as a plain string.

A chart is the better fit when the point is the shape of the numbers, a trend or a share, and a hover value matters more than reading every row. Keep the table when someone will look up one account or sort by the change. Test results are the better fit for a pass and fail run, because they have suite rows, skip, and an expected versus received block. A product spec table is the better fit when the columns are products and the rows are attributes, with a control to hide the rows that do not differ. This table is records down the page, one header per field.

Does the CSV match the order on screen?

Yes. The file is built from the sorted rows, with the column labels as the header line, not the raw keys. Currency and percent formatting is not applied inside the file. MRR is the number and 30d is the number, while the table shows the dollar sign and the percent. Fields that contain a comma, a quote or a newline are quoted.

What does the third click on a column header do?

It clears the sort by passing null to onSortChange, so the rows return to the order you passed in. The first click is ascending for a text column and descending for a numeric one. The second click flips that direction. Only one column is active. Starting a sort on another header replaces the previous one rather than stacking.