A powerful, flexible, and composable data table component built with TanStack React-Table. Features server-side pagination, sorting, multiple view modes, and URL state management.
Built with composition in mind. Mix and match components like ListView, CardView, and BottomPaginator to create custom table experiences.
Efficient server-side pagination and sorting with TanStack Start server functions. Handles large datasets seamlessly.
Shareable URLs that preserve table state. Perfect for bookmarking specific views or sharing filtered results.
Demonstrates the DataTable with React state management. Perfect for applications where you don't need URL persistence.
Shows how to integrate table state with URL parameters. Great for shareable links and browser history.
import { DataTable } from './components/dataTable/DataTable' import { ListView, BottomPaginator } from './components/dataTable' import { useDataTableState } from './components/dataTable/DataTableState' function MyTable() { const { state, handlers } = useDataTableState({ defaultPageSize: 10, defaultSort: { id: 'name', desc: false } }) const fetcher = async (pagination, sorting) => { return await fetchData(pagination, sorting) } const columns = [ { accessorKey: 'name', header: 'Name' }, { accessorKey: 'email', header: 'Email' }, { accessorKey: 'status', header: 'Status' } ] return ( <DataTable queryKey={['users']} fetcher={fetcher} columns={columns} pagination={state.pagination} onPaginationChange={handlers.onPaginationChange} sorting={state.sorting} onSortingChange={handlers.onSortingChange} > <ListView /> <BottomPaginator /> </DataTable> ) }
import { useDataTableURLState } from './components/dataTable/DataTableState' function MyTableWithURL() { const navigate = useNavigate() const search = useSearch() const { state, handlers } = useDataTableURLState( search, navigate, { defaultPageSize: 10, defaultSort: { id: 'name', desc: false } } ) // URL will automatically sync with table state // /my-page?pageIndex=2&pageSize=20&sortId=email&sortDesc=true return ( <DataTable queryKey={['users']} fetcher={fetcher} columns={columns} pagination={state.pagination} onPaginationChange={handlers.onPaginationChange} sorting={state.sorting} onSortingChange={handlers.onSortingChange} > <ListView /> <BottomPaginator /> </DataTable> ) }
import { CardView } from './components/dataTable/CardView' function MyCardTable() { return ( <DataTable queryKey={['products']} fetcher={fetcher} columns={columns} pagination={state.pagination} onPaginationChange={handlers.onPaginationChange} sorting={state.sorting} onSortingChange={handlers.onSortingChange} > <CardView className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-6" renderCard={(product) => ( <div className="bg-white dark:bg-gray-700 rounded-lg p-4 shadow"> <h3 className="font-semibold text-lg">{product.name}</h3> <p className="text-gray-600 dark:text-gray-300">{product.description}</p> <div className="mt-2 text-sm text-gray-500"> ${product.price.toLocaleString()} </div> </div> )} /> <BottomPaginator layout="centered" /> </DataTable> ) }
import { createServerFn } from '@tanstack/react-start' import z from 'zod' const getDataServerFn = createServerFn({ method: 'GET', }) .validator( z.object({ pagination: z.object({ pageIndex: z.number(), pageSize: z.number() }), sorting: z.object({ id: z.string(), desc: z.boolean(), }), }) ) .handler(async ({ data: input }) => { // Your server-side logic here const { pagination, sorting } = input // Fetch data from database const data = await fetchFromDatabase({ offset: pagination.pageIndex * pagination.pageSize, limit: pagination.pageSize, sortBy: sorting.id, sortOrder: sorting.desc ? 'DESC' : 'ASC' }) return { rows: data.items, rowCount: data.totalCount } }) // Use in component const getData = useServerFn(getDataServerFn) const fetcher = (pagination, sorting) => getData({ data: { pagination, sorting } })
Type-safe development
Powerful table logic
Full-stack framework
Utility-first styling
Built with ❤️ using TanStack Table and modern React patterns