A headless, type-safe table state framework for React.
Build complex data tables with reusable logic, predictable state and flexible data integration.
Most table libraries focus on rendering UI.
But real-world tables are about:
- managing state (sorting, pagination, filters)
- handling data flows (local vs remote)
- composing multiple components (toolbar, table, pagination)
typed-table focuses on modeling those concerns — not just rendering them.
- Strong TypeScript inference
- Headless architecture (no UI constraints)
- Reusable table state and logic
- Works with any data source (REST, GraphQL, React Query)
- Designed for complex applications
npm install @typed-table/core @typed-table/adapters @typed-table/react reactUse @typed-table/core when you want the framework-agnostic engine, or @typed-table/adapters when you want local or remote pipeline composition without the React hook.
import { column, createColumns, useTable } from "@typed-table/react";
type User = {
id: string;
name: string;
age: number;
};
const columns = createColumns<User>([
column("name", { header: "Name", sortable: true }),
column("age", { header: "Age", sortable: true }),
]);
const table = useTable<User>({
columns,
data: users,
});import { TableProvider } from "@typed-table/react";
function UsersPage() {
return (
<TableProvider table={table}>
<UsersToolbar />
<UsersTable />
<UsersPagination />
</TableProvider>
);
}typed-table is built for composability. Each component can consume the same table instance through context with useTableContext().
examples/basic-tablefor local sorting, filtering, grouping, row ordering, selection, visibility, and sizingexamples/filter-row-selectionfor context-driven composition, filtering, and selection workflowsexamples/remote-paginationfor remote pagination, sorting, grouping, faceting, and dataset-level selectionexamples/infinite-scrollfor append-oriented remote loading
type User = {
id: string;
name: string;
email: string;
age: number;
};import { column, createColumns } from "@typed-table/react";
const columns = createColumns<User>([
column("name", { header: "Name", sortable: true, filterable: true }),
column("email", { header: "Email", filterable: true }),
column("age", { header: "Age", sortable: true }),
]);import { useTable } from "@typed-table/react";
const table = useTable<User>({
columns,
data: users,
getRowId: (row) => row.id,
});import { useTableContext } from "@typed-table/react";
function UsersTable() {
const table = useTableContext<User>();
return (
<table>
<thead>
<tr>
{table.headers.map((header) => (
<th key={header.id} onClick={() => table.sortBy(header.id)}>
{header.label}
</th>
))}
</tr>
</thead>
<tbody>
{table.rows.map((row) => (
<tr key={row.id}>
{row.cells.map((cell) => (
<td key={cell.id}>{cell.render()}</td>
))}
</tr>
))}
</tbody>
</table>
);
}typed-table is data-source agnostic.
You can integrate with:
- REST APIs
- GraphQL
- React Query
- Custom data sources
const table = useTable<User>({
columns,
mode: "remote",
getRowId: (row) => row.id,
query: async ({ pagination, sorting }) => {
const response = await fetch("/api/users", {
method: "POST",
body: JSON.stringify({
page: pagination.page,
pageSize: pagination.pageSize,
sorting,
}),
});
const data = await response.json();
return {
rows: data.items,
total: data.total,
};
},
});const table = useTable<User>({
columns,
mode: "remote",
getRowId: (row) => row.id,
query: ({ pagination }) =>
queryClient.fetchQuery({
queryKey: ["users", pagination.page, pagination.pageSize],
queryFn: () => fetchUsers(pagination.page, pagination.pageSize),
}),
});For non-React integrations, use @typed-table/adapters directly.
-
Separation of concerns
Logic is independent from UI. -
Explicit state model
Table behavior is predictable and debuggable. -
End-to-end type safety
Types flow from your data to your UI.
@typed-table/core→ table engine (framework-agnostic)@typed-table/react→ React bindings@typed-table/adapters→ data integration layercomposition
@typed-table/core
↓
@typed-table/react
↓
UI components
Data sources
REST / GraphQL / React Query
↓
@typed-table/adapters
| Feature | typed-table | Traditional table components |
|---|---|---|
| Headless | ✅ | ❌ |
| Type-safe | ✅ | |
| Data-source agnostic | ✅ | ❌ |
| Composable across components | ✅ | ❌ |
| Scalable architecture | ✅ | ❌ |
- SaaS dashboards
- admin panels
- analytics tools
- data-heavy applications
examples/basic-tableexamples/filter-row-selectionexamples/remote-paginationexamples/infinite-scrolldocs/packages.mddocs/virtualization.mdCONTRIBUTING.md
This repository uses npm workspaces and requires Node.js 22 or newer.
npm install
npm run build
npm testRun the example apps:
npm run dev:basic
npm run dev:filter-selection
npm run dev:remote
npm run dev:infinite-scrollBuild all example apps:
npm run build:examplesContributions are welcome. See CONTRIBUTING.md for setup, workflow expectations, and pull request checks.
Apache-2.0