TanStack Table mit Claude Code: Hochperformante Datentabellen 2026

TanStack Table (früher React Table) ist die headless Table-Library für React — keine Styles, volle Kontrolle, vollständig typisiert. Claude Code kennt alle Features: Sorting, Filtering, Pagination, Row Selection, Column Pinning und Virtualisierung für Millionen von Rows.

Setup und erste Tabelle

SetupGrundlegende Tabelle mit Typen

# npm install @tanstack/react-table // Prompt: "Erstelle eine typisierte Datentabelle für User-Management" import { useReactTable, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel, createColumnHelper, flexRender, ColumnDef, SortingState, ColumnFiltersState, } from '@tanstack/react-table'; // Typ definieren: type User = { id: string; name: string; email: string; role: 'admin' | 'user'; createdAt: Date; active: boolean; }; // Column Helper für vollständige Typsicherheit: const columnHelper = createColumnHelper<User>(); const columns = [ columnHelper.display({ id: 'select', header: ({ table }) => ( <input type="checkbox" checked={table.getIsAllPageRowsSelected()} onChange={table.getToggleAllPageRowsSelectedHandler()} /> ), cell: ({ row }) => ( <input type="checkbox" checked={row.getIsSelected()} onChange={row.getToggleSelectedHandler()} /> ), }), columnHelper.accessor('name', { header: 'Name', cell: info => <strong>{info.getValue()}</strong>, enableSorting: true, enableColumnFilter: true, }), columnHelper.accessor('email', { header: 'E-Mail', enableSorting: true, }), columnHelper.accessor('role', { header: 'Rolle', cell: info => ( <span className={`badge ${info.getValue()}`}>{info.getValue()}</span> ), filterFn: 'equals', }), columnHelper.accessor('createdAt', { header: 'Erstellt am', cell: info => info.getValue().toLocaleDateString('de-DE'), sortingFn: 'datetime', }), columnHelper.accessor('active', { header: 'Status', cell: info => info.getValue() ? '✅ Aktiv' : '❌ Inaktiv', filterFn: 'equals', }), ];

Sorting, Filtering und Pagination

TabelleVollständige User-Tabelle mit allen Features

function UserTable({ data }: { data: User[] }) { const [sorting, setSorting] = useState<SortingState>([]); const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]); const [globalFilter, setGlobalFilter] = useState(''); const [rowSelection, setRowSelection] = useState({}); const table = useReactTable({ data, columns, state: { sorting, columnFilters, globalFilter, rowSelection }, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onGlobalFilterChange: setGlobalFilter, onRowSelectionChange: setRowSelection, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), enableRowSelection: true, initialState: { pagination: { pageSize: 20 } }, }); return ( <div> {/* Globale Suche */} <input value={globalFilter} onChange={e => setGlobalFilter(e.target.value)} placeholder="Alle Spalten durchsuchen..." /> {/* Tabelle */} <table> <thead> {table.getHeaderGroups().map(headerGroup => ( <tr key={headerGroup.id}> {headerGroup.headers.map(header => ( <th key={header.id} onClick={header.column.getToggleSortingHandler()} style={{ cursor: header.column.getCanSort() ? 'pointer' : 'default' }} > {flexRender(header.column.columnDef.header, header.getContext())} {header.column.getIsSorted() === 'asc' ? ' ↑' : ''} {header.column.getIsSorted() === 'desc' ? ' ↓' : ''} </th> ))} </tr> ))} </thead> <tbody> {table.getRowModel().rows.map(row => ( <tr key={row.id} data-selected={row.getIsSelected()}> {row.getVisibleCells().map(cell => ( <td key={cell.id}> {flexRender(cell.column.columnDef.cell, cell.getContext())} </td> ))} </tr> ))} </tbody> </table> {/* Pagination */} <div> <button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>←</button> <span>Seite {table.getState().pagination.pageIndex + 1} von {table.getPageCount()}</span> <button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>→</button> <select value={table.getState().pagination.pageSize} onChange={e => table.setPageSize(Number(e.target.value))}> {[10, 20, 50, 100].map(size => <option key={size}>{size}</option>)} </select> </div> </div> ); }

Server-Side Sorting und Filtering

Server-SideFür große Datensätze: API-basiert

// Prompt: "TanStack Table mit Server-Side Sorting/Filtering über API" function ServerTable() { const [sorting, setSorting] = useState<SortingState>([]); const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 20 }); // React Query / SWR für Data Fetching: const { data, isLoading } = useQuery({ queryKey: ['users', sorting, columnFilters, pagination], queryFn: () => fetchUsers({ sortBy: sorting[0]?.id, sortDir: sorting[0]?.desc ? 'desc' : 'asc', filters: columnFilters, page: pagination.pageIndex, pageSize: pagination.pageSize, }), placeholderData: keepPreviousData, // Verhindert Flackern beim Paginieren }); const table = useReactTable({ data: data?.rows ?? [], columns, state: { sorting, columnFilters, pagination }, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onPaginationChange: setPagination, getCoreRowModel: getCoreRowModel(), manualSorting: true, // Server übernimmt Sorting manualFiltering: true, // Server übernimmt Filtering manualPagination: true, // Server übernimmt Pagination pageCount: data?.pageCount ?? -1, }); if (isLoading) return <TableSkeleton />; // ... render table }
Client vs. Server-Side: Client-Side für <10.000 Rows (alle Daten im Browser). Server-Side für größere Datensätze — API übernimmt Sorting, Filtering, Pagination. Claude Code erkennt die Datenmenge und wählt automatisch den richtigen Ansatz.

Virtualisierung: Millionen von Rows

VirtualisierungTanStack Virtual + Table für Mega-Tabellen

// npm install @tanstack/react-virtual // Prompt: "Virtualisierte Tabelle für 100.000+ Rows" import { useVirtualizer } from '@tanstack/react-virtual'; function VirtualTable({ data }: { data: User[] }) { const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), }); const { rows } = table.getRowModel(); const parentRef = useRef<HTMLDivElement>(null); const virtualizer = useVirtualizer({ count: rows.length, getScrollElement: () => parentRef.current, estimateSize: () => 48, // Geschätzte Row-Höhe in px overscan: 10, // Puffer außerhalb des Viewports }); return ( <div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}> <div style={{ height: virtualizer.getTotalSize() + 'px', position: 'relative' }}> {virtualizer.getVirtualItems().map(virtualRow => { const row = rows[virtualRow.index]; return ( <tr key={row.id} style={{ position: 'absolute', top: virtualRow.start + 'px', height: virtualRow.size + 'px', }}> {row.getVisibleCells().map(cell => ( <td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td> ))} </tr> ); })} </div> </div> ); } // 100.000 Rows: nur ~10-20 DOM-Nodes gleichzeitig — 60fps garantiert!

Datentabellen-Modul im Kurs

Im Claude Code Mastery Kurs: vollständiges TanStack Table Modul mit Client-Side und Server-Side Tabellen, Row Selection, Column Pinning, Virtualisierung und Export-Funktionen — inkl. shadcn/ui Integration.

14 Tage kostenlos testen →