asafefe.dev

Data Table

New

A sortable, searchable table. Rows glide into their new order, matches are highlighted, and selecting rows slides up a bulk action bar.

motionlucide-reactutils@soultel/use-reduced-motion-safe
8 rows
Invoices
Parcel CoINV-1039$4,120
Kite AnalyticsINV-1037$3,350
Northwind TradersINV-1042$2,480
Orbit FitnessINV-1035$1,875
Lumen LabsINV-1041$1,290
FieldnoteINV-1038$980
Tilde StudioINV-1040$760
Acme BakeryINV-1036$410

Installation

$ pnpm dlx shadcn@latest add @soultel/data-table

No namespace set up? npx shadcn@latest add https://asafefe.dev/r/data-table.json works too.

Manual installation
  1. 1. Install the dependencies.
    terminal1 lines
    npm install motion lucide-react
  2. 2. Copy the source from the Code tab into components/data-table.tsx.

Usage

example.tsx21 lines
import { DataTable, highlight, type DataTableColumn } from "@/components/data-table"

type Invoice = { id: string; customer: string; amount: number; status: string }

const columns: DataTableColumn<Invoice>[] = [
  { key: "customer", header: "Customer", accessor: (r) => r.customer, sortable: true },
  { key: "status", header: "Status", accessor: (r) => r.status, cell: (r, q) => <b>{highlight(r.status, q)}</b> },
  { key: "amount", header: "Amount", accessor: (r) => r.amount, sortable: true, align: "right" },
]

export function Invoices({ rows }: { rows: Invoice[] }) {
  return (
    <DataTable
      data={rows}
      columns={columns}
      getRowId={(r) => r.id}
      selectable
      bulkActions={(ids, clear) => <button onClick={() => { exportCsv(ids); clear() }}>Export</button>}
    />
  )
}

Props

PropTypeDefaultDescription
dataT[]-Rows.
columnsDataTableColumn<T>[]-key, header, accessor, and optional cell, sortable, align, hideBelow.
getRowId(row: T) => string-Stable id per row.
getRowLabel(row: T) => string-Name read out by each row checkbox.
selectablebooleanfalseAdds checkboxes and the bulk action bar.
selected / defaultSelectedstring[]-Controlled or initial selected ids, with onSelectedChange.
bulkActions(ids, clear) => ReactNode-Buttons in the bulk action bar.
sort / defaultSort{ key: string; direction: "asc" | "desc" } | null-Controlled or initial sort, with onSortChange. Headers cycle asc, desc, off.
searchablebooleantrueShow the search field. Matches get a highlight.
empty(query: string) => ReactNode-Custom empty state.
highlight(text, query)=> ReactNode-Exported helper for custom cells.