Skip to content

@requence/table

Headless virtualized table with compound component API, Suspense-compatible data caching, and column width persistence.

Virtual Scrolling

Render thousands of rows with constant memory usage. Only visible rows plus a configurable overscan buffer are mounted — the rest is pure CSS translateY.

Compound API

Declarative compound component API. Compose Header, Column, Body, Row, Cell, and more with a clean, composable interface.

Suspense Caching

useTableCache integrates with React Suspense for initial loads and handles paginated fetching, sort-aware mutations, and real-time upserts out of the box.

Column Persistence

Users can resize columns by dragging. useTableColumnWidths persists widths to localStorage and supports both pixel and fractional (fr) values.

import { VirtualTable, useTableCache } from '@requence/table'
function Users() {
const cache = useTableCache('users', {
pageSize: 50,
getItemId: (u) => u.id,
compare: (a, b) => a.name.localeCompare(b.name),
fetchItems: async (offset, limit) => {
const res = await fetch(`/api/users?offset=${offset}&limit=${limit}`)
return res.json()
},
})
return (
<VirtualTable
totalCount={cache.totalCount}
rowHeight={32}
onRangeChange={cache.handleRangeChange}
>
<VirtualTable.Header>
<VirtualTable.Column width="2fr">Name</VirtualTable.Column>
<VirtualTable.Column width="2fr">Email</VirtualTable.Column>
<VirtualTable.Column width={100}>Role</VirtualTable.Column>
</VirtualTable.Header>
<VirtualTable.Body>
{(index) => {
const user = cache.getItem(index)
if (!user) return null
return (
<VirtualTable.Row>
<VirtualTable.Cell>{user.name}</VirtualTable.Cell>
<VirtualTable.Cell>{user.email}</VirtualTable.Cell>
<VirtualTable.Cell>{user.role}</VirtualTable.Cell>
</VirtualTable.Row>
)
}}
</VirtualTable.Body>
<VirtualTable.Empty>No users found.</VirtualTable.Empty>
<VirtualTable.Footer>
{({ start, end }) => `Rows ${start + 1}${end}`}
</VirtualTable.Footer>
</VirtualTable>
)
}
Terminal window
npm install @requence/table