developer guide
Remote source
For datasets too large to hold: the server does the sort, filter, grouping, totals and pivot, and the grid fetches blocks on demand as the user scrolls.
The server does the work
The remote source is the mode for data too large to hold in the browser. Grouping, totals, sorting, filtering and pivoting are all delegated to the server, and the grid requests rows one group level at a time as the viewport reaches them. That is what lets a grid sit in front of a dataset of any size and stay responsive: the browser holds a few blocks, and the server answers a query over the whole set.
createGrid(el, {
columns,
rowKey: 'id',
source: {
mode: 'remote',
pageSize: 100,
async fetch(req) {
// req carries the whole query, at protocol version 1:
// range { start, end } the block wanted
// sort [{ col, dir }, …] multi-column
// filters the condition tree
// quick free-text search
// groupBy columns to group on
// groupPath which group level is being expanded
// totals columns to total
// pivotBy columns to pivot on
// context your own opaque value, passed straight through
const res = await api.query(req, { signal: req.signal });
return { rows: res.rows, total: res.total }; // or 'count'
},
},
});
The request is a published protocol
Every request your callback receives carries protocol: 1 and a documented shape, so you
target the published version rather than reverse-engineering what the current release happens to send.
It is not an opaque object: the filters field is the same condition tree documented across
the rest of the guide, and the sort is a plain array. Beyond the range, sort and filter that the
paged source also sends, the remote request adds
groupBy, groupPath, pivotBy, totals and your own
context, so a server that can group and aggregate does that work instead of the browser.
Grouping fetches one level at a time
When the grid is grouped, it asks the server for the top-level groups first, and for a group's children only when that group is expanded. Each expanded group owns its own block cache, so expanding one group does not invalidate its siblings, and expansion state survives a reload because it is keyed by a stable group key rather than by scroll position. Totals arrive on the group rows from the server and are used as given; the grid does not recompute a figure the server already calculated.
Blocks, caching and superseding
Blocks are fetched as the viewport reaches them and cached. Changing the sort or the filter invalidates
the cache and re-queries, because the server may return an entirely different window for the same range.
A request that is superseded by a newer one aborts itself through the signal on the request, so a fast
scroll or a quick succession of filters does not leave stale responses racing to land. Return a
total (or count, both are honoured) and the scrollbar is exact; omit it and
the source discovers the length as it goes.
As with the paged source, a configured host filter is never sent and warns once, because filtering only the fetched window would give wrong results. The grid does not show a wrong answer in place of a visible one.
Or let an adapter write the query
A remote source hands you the whole request and leaves the translation to your endpoint. If your data lives behind a query engine, a pushdown adapter inverts that: you declare what the engine can answer and the grid builds the query and finishes the rest. OData, DuckDB, REST and DFQL adapters all ship, and each produces an ordinary remote source, so everything on this page applies to them unchanged.
See it running: remote, with the server doing the work. For the full set of options, start from connect your data.