Remote Data Grid
The remote variant fetches data asynchronously via a query function instead of receiving pre-loaded data. Import from @repo/table/remote.
Basic Usage
<script lang="ts">
import { createColumnHelper, DataGrid, useDataGrid } from '@repo/table/remote';
import { getUsers } from './users.remote';
const ch = createColumnHelper<User>()
const { table, dataGrid } = useDataGrid({
tableOptions: {
columns: ch.columns([
ch.accessor('name', { header: 'Name' }),
ch.accessor('email', { header: 'Email' }),
]),
},
query: getUsers,
getRowLink: (row) => `/users/${row.id}`,
});
</script>
<DataGrid.Root {dataGrid} {table} title="Users" add="/users/add" />
useDataGrid returns the table and data-grid state synchronously. The remote query itself updates reactively.
RemoteDataGridOptions
| Option | Type | Description |
|---|---|---|
tableOptions | DataGridTableOptions<T> | Feature-bound TanStack Table config |
query | RemoteQueryFunction<OverviewQueryParams<F>, PaginatedResult<T>> | Async function that fetches data |
getRowLink | (row: Row<T>) => string? | Row link generator |
filterSchema | z.ZodObject? | Zod schema for filters |
Query Function
The query function receives OverviewQueryParams:
interface OverviewQueryParams<F> {
filters?: z.infer<F>
sorting: SortingState
pagination: PaginationState
}
Must return PaginatedResult<T> ({ data: T[], count: number }).
DataGrid Return Value
The remote dataGrid object exposes reactive getters and setters backed by TanStack atoms:
| Property | Type | Description |
|---|---|---|
paginationResultCount | number | Total result count |
getRowLink | GetRowLink<T> | Row link function |
filters | z.infer<F> | Current filter state |
setFilters | (value?) => void | Update filters and reload |
sorting | SortingState | Current sort state |
setSorting | (state) => void | Update sorting and reload |
pagination | PaginationState | Current pagination state |
setPagination | (state) => void | Update pagination and reload |
loading | boolean | Whether data is being fetched |
refresh | () => void | Re-fetch with current params |
Remote Filters
Use DataGrid.FilterForm inside DataGrid.Root children:
<script lang="ts">
import { DataGrid, useDataGrid } from '@repo/table/remote';
import { z } from 'zod/v4';
const filterSchema = z.object({
name: z.string().optional(),
status: z.enum(['active', 'inactive']).optional(),
});
const { table, dataGrid } = useDataGrid({
tableOptions: { columns: [...] },
query: getUsers,
filterSchema,
});
</script>
<DataGrid.Root {dataGrid} {table} title="Users">
<DataGrid.FilterForm schema={filterSchema} />
</DataGrid.Root>
FilterForm reads dataGrid from Svelte context set by DataGrid.Root. It renders Apply/Clear buttons automatically.
Custom filter layouts receive fields and the current filter value:
<DataGrid.FilterForm schema={filterSchema}>
{#snippet children({ fields, value })}
<TypedForm.Field field={fields.status} bind:value={value.status} input={TypedForm.SelectInput} optionItems={statusOptions} />
{/snippet}
</DataGrid.FilterForm>
createOverviewQuerySchema
Server-side helper to validate query params in your remote function:
import { createOverviewQuerySchema } from '@repo/table/remote'
import { z } from 'zod/v4'
const filterSchema = z.object({
name: z.string(),
status: z.enum(['active', 'inactive']),
})
const querySchema = createOverviewQuerySchema(filterSchema)
// Produces: z.object({
// pagination: z.object({ pageIndex: z.number().min(0), pageSize: z.number().min(1) }),
// sorting: z.array(z.object({ id: z.string(), desc: z.boolean() })),
// filters: filterSchema.partial().optional(),
// })
URL State
The remote data grid uses qs for URL serialization. Params:
?sort=name:ASC?page=2&pageSize=10?filter[name]=Alice&filter[status]=active
State updates use SvelteKit shallow replaceState() to update the URL without route navigation.
Type Helper
Extract the data type from a query function:
import type { QueryDataPoint } from '@repo/table/remote'
type User = QueryDataPoint<typeof getUsers>