Remote Data
Seizen Table supports a Remote Mode that enables seamless integration with external data sources. In this mode, filtering, sorting, and pagination are handled by your external data source (e.g., REST API, GraphQL, TanStack DB), while Seizen Table manages the UI state.
Enabling Remote Mode
Section titled “Enabling Remote Mode”Enable Remote Mode by adding the remote option to useSeizenTable:
import { useSeizenTable, SeizenTable } from "@izumisy/seizen-table";
// Without paginationconst table = useSeizenTable({ data: filteredUsers, // Pre-filtered data from external source columns, remote: true,});
// With pagination (requires totalRowCount for page calculation)const table = useSeizenTable({ data: filteredUsers, columns, remote: { totalRowCount: 1000 },});Data State Helper (useRemoteData)
Section titled “Data State Helper (useRemoteData)”If you want a small helper to manage remote-related state (data/loading/error/totalCount/cursors), use useRemoteData from @izumisy/seizen-table-plugins/remote.
import { useSeizenTable, SeizenTable } from "@izumisy/seizen-table";import { useRemoteData } from "@izumisy/seizen-table-plugins/remote";
const remote = useRemoteData<User>();
const table = useSeizenTable({ data: remote.data, columns, remote: remote.getRemoteOptions(),});
return <SeizenTable table={table} loading={remote.loading} />;What it does
Section titled “What it does”useRemoteData is an optional helper hook that manages only data-related state for Remote Mode.
It does not manage table UI state (pagination/sorting/filters); those are still owned by useSeizenTable.
- Data state:
data,loading,error - Server information:
totalCount(used to calculate page count) - Cursor utilities:
getCursor(pageIndex),clearCursors()for cursor-based pagination - Remote option helper:
getRemoteOptions()to feedremote: true/remote: { totalRowCount }appropriately
Why use it
Section titled “Why use it”- Keeps responsibilities separated: table state vs. network/data state
- Avoids repeating the same
useStatebundle across screens/tables - Makes cursor-based pagination easier to implement consistently
- Gives a single, predictable place to set
loading/errorand the servertotalCount
How It Works
Section titled “How It Works”| Mode | Filtering/Sorting/Pagination |
|---|---|
| Default | TanStack Table processes data internally |
| Remote | External source processes data; UI state is synchronized |
In Remote Mode:
- User interacts with filter/sort/pagination controls
- Internal state updates (for UI synchronization)
- Events are emitted (
filter-change,sorting-change,pagination-change) - Your app subscribes to events and updates the external data source
- New
dataprop is passed to the table
In many remote setups, a sorting/filter change should reset pagination to the first page. If you use cursor-based pagination, you usually also want to clear cursors at the same time:
remote.clearCursors();table.setPageIndex(0);Loading State
Section titled “Loading State”Use the loading prop to show a loading overlay while fetching data:
<SeizenTable table={table} loading={isLoading}/>
// With custom loader<SeizenTable table={table} loading={isLoading} loaderComponent={<MyCustomSpinner />}/>CSS Variables
Section titled “CSS Variables”Customize the loading overlay appearance:
:root { --szui-loading-overlay-bg: rgba(255, 255, 255, 0.8); --szui-spinner-size: 32px; --szui-spinner-color: #3b82f6;}Complete Example
Section titled “Complete Example”Here’s a complete example integrating with a REST API using useRemoteData:
import { useCallback, useEffect } from "react";import { useSeizenTable, useSeizenTableEvent, SeizenTable,} from "@izumisy/seizen-table";import { FilterPlugin } from "@izumisy/seizen-table-plugins/filter";import { useRemoteData } from "@izumisy/seizen-table-plugins/remote";
function UsersTable() { const remote = useRemoteData<User>();
const table = useSeizenTable({ data: remote.data, columns, plugins: [FilterPlugin.configure({ disableGlobalSearch: true })], remote: remote.getRemoteOptions(), });
const resetRemotePagination = useCallback(() => { remote.clearCursors(); table.setPageIndex(0); }, [remote, table]);
const fetchUsers = useCallback( async ( pagination: { pageIndex: number; pageSize: number }, sorting: { id: string; desc: boolean }[], filters: { id: string; value: unknown }[] ) => { remote.setLoading(true); remote.setError(null);
try { const query = new URLSearchParams();
// Convert filter state to query params (example) filters.forEach((f) => { const { operator, value } = f.value as { operator: string; value: string; }; query.append(`filter[${f.id}][${operator}]`, value); });
// Add sorting sorting.forEach((s) => { query.append("sort", `${s.desc ? "-" : ""}${s.id}`); });
// Add pagination query.append("page", String(pagination.pageIndex + 1)); query.append("limit", String(pagination.pageSize));
// Optional: cursor-based pagination const cursor = remote.getCursor(pagination.pageIndex - 1); if (cursor) query.append("cursor", cursor);
const res = await fetch(`/api/users?${query}`); if (!res.ok) throw new Error(`Request failed: ${res.status}`); const json = await res.json();
remote.setData(json.items, { totalCount: json.total, cursor: json.nextCursor, }); } catch (e) { remote.setError(e instanceof Error ? e : new Error("Fetch failed")); remote.setData([], { totalCount: 0 }); } finally { remote.setLoading(false); } }, [remote] );
// Fetch data on pagination change useSeizenTableEvent(table, "pagination-change", (pagination) => { fetchUsers(pagination, table.getSortingState(), table.getFilterState()); });
// Sorting changes usually reset to the first page useSeizenTableEvent(table, "sorting-change", (sorting) => { resetRemotePagination(); fetchUsers( { pageIndex: 0, pageSize: table.getPaginationState().pageSize }, sorting, table.getFilterState() ); });
// Filter changes usually reset to the first page useSeizenTableEvent(table, "filter-change", (filters) => { resetRemotePagination(); fetchUsers( { pageIndex: 0, pageSize: table.getPaginationState().pageSize }, table.getSortingState(), filters ); });
// Initial fetch useEffect(() => { fetchUsers( table.getPaginationState(), table.getSortingState(), table.getFilterState() ); }, [fetchUsers, table]);
return <SeizenTable table={table} loading={remote.loading} />;}Checking Remote Mode in Plugins
Section titled “Checking Remote Mode in Plugins”Plugins can check if Remote Mode is enabled via table.remote:
function MyPluginComponent() { const { table } = usePluginContext();
if (table.remote) { // Adjust behavior for Remote Mode // e.g., hide global search return null; }
return <GlobalSearchInput />;}