Data table with sorting, filtering, and pagination. AI output used client-side sorting, cleared data during reloads, and missed table accessibility attributes. The production version fixes all eight issues found in review.
1export function DataTable<TData, TValue>({2 columns, data, loading = false,3}: DataTableProps<TData, TValue>) {4 const [sorting, setSorting] = useState<SortingState>([]);5 const [rowSelection, setRowSelection] = useState({});67 const table = useReactTable({8 data,9 columns,10 state: { sorting, rowSelection },11 onSortingChange: setSorting,12 onRowSelectionChange: setRowSelection,13 getCoreRowModel: getCoreRowModel(),14 getSortedRowModel: getSortedRowModel(),15 getPaginationRowModel: getPaginationRowModel(),16 enableRowSelection: true,17 });1819 if (loading) {20 return <DataTableLoading columnCount={columns.length} />;21 }2223 return (24 <div className="space-y-4">25 <Table>26 <TableHeader>27 {table.getHeaderGroups().map((headerGroup) => (28 <TableRow key={headerGroup.id}>29 {headerGroup.headers.map((header) => (30 <TableHead key={header.id}>31 {flexRender(32 header.column.columnDef.header,33 header.getContext()34 )}35 </TableHead>36 ))}37 </TableRow>38 ))}39 </TableHeader>40 <TableBody>41 {table.getRowModel().rows.map((row) => (42 <TableRow key={row.id}>43 {row.getVisibleCells().map((cell) => (44 <TableCell key={cell.id}>45 {flexRender(46 cell.column.columnDef.cell,47 cell.getContext()48 )}49 </TableCell>50 ))}51 </TableRow>52 ))}53 </TableBody>54 </Table>55 </div>56 );57}1export function DataTable<TData, TValue>({2 columns, data, loading = false,3}: DataTableProps<TData, TValue>) {4 const [sorting, setSorting] = useState<SortingState>([]);5 const [rowSelection, setRowSelection] = useState({});67 const table = useReactTable({8 data,9 columns,10 state: { sorting, rowSelection },11 onSortingChange: setSorting,12 onRowSelectionChange: setRowSelection,13 getCoreRowModel: getCoreRowModel(),14 manualSorting: true,15 getPaginationRowModel: getPaginationRowModel(),16 enableRowSelection: true,17 });1819 return (20 <div className={cn("space-y-4", loading && "opacity-60")}>21 <Table>22 <TableHeader>23 {table.getHeaderGroups().map((headerGroup) => (24 <TableRow key={headerGroup.id}>25 {headerGroup.headers.map((header) => (26 <TableHead key={header.id}>27 {flexRender(28 header.column.columnDef.header,29 header.getContext()30 )}31 </TableHead>32 ))}33 </TableRow>34 ))}35 </TableHeader>36 <TableBody>37 {table.getRowModel().rows.map((row) => (38 <TableRow key={row.id}>39 {row.getVisibleCells().map((cell) => (40 <TableCell key={cell.id}>41 {flexRender(42 cell.column.columnDef.cell,43 cell.getContext()44 )}45 </TableCell>46 ))}47 </TableRow>48 ))}49 </TableBody>50 </Table>51 </div>52 );53}1export function DataTable<TData, TValue>({2 columns, data, loading = false,3}: DataTableProps<TData, TValue>) {4 const [sorting, setSorting] = useState<SortingState>([]);5 const [rowSelection, setRowSelection] = useState({});67 const table = useReactTable({8 data,9 columns,10 state: { sorting, rowSelection },11 onSortingChange: setSorting,12 onRowSelectionChange: setRowSelection,13 getCoreRowModel: getCoreRowModel(),14 getSortedRowModel: getSortedRowModel(),15 getPaginationRowModel: getPaginationRowModel(),16 enableRowSelection: true,17 });1819 if (loading) {20 return <DataTableLoading columnCount={columns.length} />;21 }2223 return (24 <div className="space-y-4">25 <Table>26 <TableHeader>27 {table.getHeaderGroups().map((headerGroup) => (28 <TableRow key={headerGroup.id}>29 {headerGroup.headers.map((header) => (30 <TableHead key={header.id}>31 {flexRender(32 header.column.columnDef.header,33 header.getContext()34 )}35 </TableHead>36 ))}37 </TableRow>38 ))}39 </TableHeader>40 <TableBody>41 {table.getRowModel().rows.map((row) => (42 <TableRow key={row.id}>43 {row.getVisibleCells().map((cell) => (44 <TableCell key={cell.id}>45 {flexRender(46 cell.column.columnDef.cell,47 cell.getContext()48 )}49 </TableCell>50 ))}51 </TableRow>52 ))}53 </TableBody>54 </Table>55 </div>56 );57}The AI used TanStack Table's built-in client-side sorting. This only sorts the current page of data, not the full server-side dataset. The spec required server-side sorting via API calls.
When loading is true, the entire table is replaced with a skeleton. This causes a jarring flash of "no data" between page changes. Stale data should be preserved at reduced opacity.
Server-side sorting is enabled by setting manualSorting: true and removing getSortedRowModel(). Sort changes now trigger an API re-fetch with updated sort parameters.
Instead of replacing the table with a skeleton, the loading state applies opacity-60 to the existing data. Users see the previous rows while new data loads, preventing layout shift.