Pagination
The library supports paginated document loading out of the box. Your DocumentSource.fetch returns a PageResult that tells the library how to fetch the next or previous page.
Pagination Strategies
Section titled “Pagination Strategies”Two strategies are supported:
Cursor-based — Your API returns an opaque cursor string. The library passes it back to fetch the next page. Best for real-time data where rows can be inserted/deleted between requests.
// DocumentSource.fetch returns:{ data: documents, totalCount: 150, next: { cursor: "eyJpZCI6MTAwfQ==" }, // opaque cursor previous: { cursor: "eyJpZCI6NTB9" },}Offset-based — Classic skip/limit. The library sends an offset and limit to your API.
// DocumentSource.fetch returns:{ data: documents, totalCount: 150, next: { offset: 50, limit: 25 }, previous: { offset: 0, limit: 25 },}The library doesn’t care which strategy you use — it stores whatever pagination token your source returns and passes it back on the next fetch.
Setting Page Size
Section titled “Setting Page Size”Set pageSize in your initialize function:
const state = useCollectionManager({ collectionId: "my-collection", user: "user-1", initialize: async () => ({ collectionSource, documentSource, pageSize: 25, // rows per page }),});Pagination API
Section titled “Pagination API”Once you have a CollectionManager, use these methods to navigate pages:
const manager = state.manager;const viewId = manager.views[0].id;
// Check if more pages are availablemanager.hasNextPage(viewId); // booleanmanager.hasPreviousPage(viewId); // boolean
// Navigateawait manager.fetchNextPage(viewId);await manager.fetchPreviousPage(viewId);await manager.goToPage(viewId, 3); // jump to page 3 (offset-based only)
// Read pagination statemanager.getTotalCount(viewId); // number | undefinedmanager.getPaginationStatus(viewId); // "fetching" | "idle"manager.getPaginationState(viewId); // full state objectPaginationState
Section titled “PaginationState”interface PaginationState { results: string[]; // document IDs on the current page totalCount: number | undefined; // total rows (if the source provides it) currentPagination: PaginationStrategy | undefined; nextPagination: PaginationStrategy | undefined; previousPagination: PaginationStrategy | undefined;}Full Example: Paginated Table with Controls
Section titled “Full Example: Paginated Table with Controls”import { useCollectionManager, useCollectionTableView, defaultPropertyDefinitions, TableView,} from "@blocknote/block-view/react";import { RestCollectionSource, RestDocumentSource } from "@blocknote/block-view/core/sources/rest";import type { CollectionManager } from "@blocknote/block-view/core";import "@blocknote/block-view/react/styles.css";import "@blocknote/block-view/react/adapters/styles.css";import { useState, useEffect } from "react";
function PaginatedTable({ manager, viewId }: { manager: CollectionManager; viewId: string }) { const { table } = useCollectionTableView({ collectionManager: manager, viewId, propertyDefinitions: defaultPropertyDefinitions, });
// Force re-render when pagination state changes const [, forceUpdate] = useState(0); useEffect(() => { manager.addHooks({ documentsHydrated: () => forceUpdate((n) => n + 1), }); }, [manager]);
const totalCount = manager.getTotalCount(viewId); const hasNext = manager.hasNextPage(viewId); const hasPrev = manager.hasPreviousPage(viewId); const isFetching = manager.getPaginationStatus(viewId) === "fetching";
return ( <div> <TableView table={table} editable /> <div style={{ display: "flex", gap: 8, marginTop: 8 }}> <button onClick={() => manager.fetchPreviousPage(viewId)} disabled={!hasPrev || isFetching}> Previous </button> <button onClick={() => manager.fetchNextPage(viewId)} disabled={!hasNext || isFetching}> Next </button> {totalCount !== undefined && <span>Total: {totalCount} rows</span>} {isFetching && <span>Loading...</span>} </div> </div> );}
export default function App() { const state = useCollectionManager({ collectionId: "my-collection", user: "user-1", initialize: async () => ({ collectionSource: new RestCollectionSource({ baseUrl: "/api" }), documentSource: new RestDocumentSource({ baseUrl: "/api" }), pageSize: 25, }), });
if (state.status === "loading") return <p>Loading...</p>; if (state.status === "error") return <p>Error: {state.error.message}</p>;
return <PaginatedTable manager={state.manager} viewId={state.manager.views[0].id} />;}Refreshing Data
Section titled “Refreshing Data”Force a re-fetch of the current page:
await manager.refreshView(viewId);This discards the current document set and re-fetches from the source, preserving the current pagination position.