Skip to main content

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 { DataGrid, useDataGrid } from '@repo/table/remote';
import { getUsers } from './users.remote';

const { table, dataGrid } = await useDataGrid({
tableOptions: {
columns: [
{ id: 'name', header: 'Name', accessorKey: 'name' },
{ id: 'email', header: 'Email', accessorKey: 'email' },
],
},
query: getUsers,
getRowLink: (row) => `/users/${row.original.id}`,
});
</script>

<DataGrid.Root {dataGrid} {table} title="Users" add="/users/add" />

useDataGrid is async -- use top-level await in Svelte 5 async pages/components.

RemoteDataGridOptions

OptionTypeDescription
tableOptionsPartial<TableOptions<T>>TanStack Table config
queryRemoteQueryFunction<OverviewQueryParams<F>, PaginatedResult<T>>Async function that fetches data
getRowLink(row: Row<T>) => string?Row link generator
filterSchemaz.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:

PropertyTypeDescription
paginationResultCountnumberTotal result count
getRowLinkGetRowLink<T>Row link function
filtersz.infer<F>Current filter state
setFilters(value?) => voidUpdate filters and reload
sortingSortingStateCurrent sort state
setSorting(state) => voidUpdate sorting and reload
paginationPaginationStateCurrent pagination state
setPagination(state) => voidUpdate pagination and reload
loadingbooleanWhether data is being fetched
refresh() => voidRe-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 } = await 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.

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 call goto() to update the URL without navigation.

Type Helper

Extract the data type from a query function:

import type { QueryDataPoint } from '@repo/table/remote';

type User = QueryDataPoint<typeof getUsers>;