Data Table
import { DataTable, DataTableColumnHeader } from '@hanzo/ui'
Basic
One column per field, read straight off the row by `accessorKey`.
Status
Email
Amount
0 of 5 row(s) selected.
export function Basic() {const columns: DataTableColumnDef<Payment>[] = [{ id: "status", accessorKey: "status", header: "Status" },{ id: "email", accessorKey: "email", header: "Email" },{ id: "amount", accessorKey: "amount", header: "Amount", align: "right" },]return <DataTable columns={columns} data={payments} />}
Sortable and filterable
A custom `cell` formats the amount and colors the status; `DataTableColumnHeader` gives the email column a click-to-sort button; the toolbar's text field searches it.
Status
0 of 5 row(s) selected.
export function SortableFilterable() {const columns: DataTableColumnDef<Payment>[] = [{id: "status",accessorKey: "status",header: "Status",cell: ({ row }) => {const status = row.getValue("status") as Payment["status"]const variant = status === "failed" ? "destructive" : status === "success" ? "default" : "secondary"return <Badge variant={variant}>{status}</Badge>},},{id: "email",accessorKey: "email",header: ({ column }) => <DataTableColumnHeader column={column} title="Email" />,},{id: "amount",accessorKey: "amount",header: ({ column }) => <DataTableColumnHeader column={column} title="Amount" />,align: "right",cell: ({ row }) =>new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(row.getValue("amount") as number),},]return <DataTable columns={columns} data={payments} filterColumnId="email" filterPlaceholder="Filter emails…" pageSize={3} />}
Selectable with row actions
An `id: 'select'` column gets its checkbox for free; an `id: 'actions'` column is just a normal `cell` reading `row.original`, the same convention the upstream guide's own demo uses.
Email
Amount
actions
0 of 5 row(s) selected.
export function SelectableWithActions() {const columns: DataTableColumnDef<Payment>[] = [{ id: "select", enableSorting: false, enableHiding: false },{ id: "email", accessorKey: "email", header: "Email" },{ id: "amount", accessorKey: "amount", header: "Amount", align: "right" },{id: "actions",enableHiding: false,cell: ({ row }) => (<Button variant="ghost" size="sm" onClick={() => navigator.clipboard?.writeText(row.original.id)}>Copy ID</Button>),},]return <DataTable columns={columns} data={payments} />}
Types
export type DataTableAlign = 'left' | 'center' | 'right'
export type DataTableSortDirection = 'asc' | 'desc' | false
export interface DataTableColumnApi<TData> {readonly id: stringgetCanSort: () => booleangetIsSorted: () => DataTableSortDirectiontoggleSorting: (desc?: boolean) => voidgetCanHide: () => booleangetIsVisible: () => booleantoggleVisibility: (visible?: boolean) => void}
export interface DataTableRow<TData> {readonly id: stringreadonly original: TDatagetValue: (columnId: string) => unknowngetIsSelected: () => booleantoggleSelected: (value?: boolean) => void}
export interface DataTableColumnDef<TData> {id: string/** Read directly off the row when no `cell` is given. */accessorKey?: keyof TDataheader?: ReactNode | ((ctx: { column: DataTableColumnApi<TData> }) => ReactNode)cell?: (ctx: { row: DataTableRow<TData> }) => ReactNode/** A CSS grid track for this column. Defaults to `1fr`. */width?: number | stringalign?: DataTableAlignenableSorting?: booleanenableHiding?: boolean/** The value compared when this column is the active sort. Defaults to `accessorKey`. */sortingValue?: (row: TData) => string | number/** The text searched when this column is the active filter. Defaults to `accessorKey`. */filterValue?: (row: TData) => string}
export interface DataTableInstance<TData> {getColumn: (id: string) => DataTableColumnApi<TData> | undefinedgetAllColumns: () => DataTableColumnApi<TData>[]getRowModel: () => { rows: DataTableRow<TData>[] }getFilteredRowModel: () => { rows: DataTableRow<TData>[] }getFilteredSelectedRowModel: () => { rows: DataTableRow<TData>[] }getIsAllPageRowsSelected: () => booleangetIsSomePageRowsSelected: () => booleantoggleAllPageRowsSelected: (value?: boolean) => voidgetCanPreviousPage: () => booleangetCanNextPage: () => booleanpreviousPage: () => voidnextPage: () => voidgetPageCount: () => number}
export interface DataTableProps<TData> {columns: DataTableColumnDef<TData>[]data: TData[]/** Identifies a row for selection/sort stability. Defaults to its index. */getRowId?: (row: TData, index: number) => string/** The column id the toolbar's text field searches. Omit to hide the field. */filterColumnId?: stringfilterPlaceholder?: string/** Rows per page. `0` (the default) shows every row with no pager. */pageSize?: numberemptyMessage?: ReactNodeonRowSelectionChange?: (rows: TData[]) => void}
export interface DataTableColumnHeaderProps<TData> {column: DataTableColumnApi<TData>title: ReactNodeclassName?: string}
Exports
DataTableDataTableColumnHeadertype DataTableColumnApitype DataTableColumnDeftype DataTableColumnHeaderPropstype DataTableInstancetype DataTablePropstype DataTableRowtype DataTableSortDirection