The grid is server-first: by default it pages, sorts and filters on the server and only ever holds the rows of the current page in memory.
<data-grid src="/api/users" sortable filterable selectable></data-grid>The src attribute (or the src option) creates a FetchDataSource. Every
query change reloads the data from the server.
import { DataGrid } from "data-grid-component";
import { FetchDataSource } from "data-grid-component/data-source";
const grid = new DataGrid({
dataSource: new FetchDataSource("/api/users", {
// optional, defaults to identity (QueryState is sent as-is)
serializeQuery: (query) => ({
page: query.page,
pageSize: query.pageSize,
sort: query.sort,
filters: query.filters,
}),
}),
});The current QueryState is the single source of truth:
{
page: 1,
pageSize: 10,
search: "dupont",
sort: [{ field: "name", direction: "asc" }],
filters: { status: { operator: "eq", value: "active" } },
}By default the whole state is serialized with bracket notation through
encodeSearchParams:
page=1&pageSize=10&search=dupont&sort[0][field]=name&sort[0][direction]=asc&filters[status][operator]=eq&filters[status][value]=active
Provide serializeQuery to map the state to your own server protocol.
search is a single global search term, distinct from the column filters
(search AND filters). The server decides which fields it covers — it is a
capability of the dataset, not a naive concatenation of the returned columns.
The client only ever sends the term, never a list of search fields.
A server must whitelist sortable/filterable/searchable fields and filter operators. Client-provided field names must never be interpolated directly into SQL.
For ArrayDataSource a generic case-insensitive contains over the scalar
values of each row is applied; this is a convenient local default, not the
contract imposed on backends.
The server must return a PageResult:
{
"rows": [{ "id": 1, "name": "Ada" }],
"total": 142,
"meta": {
"unfilteredTotal": 998,
"filters": { "status": [{ "value": "active", "text": "Active" }] }
}
}rows- the rows of the requested page.total- number of rows matching the current query (after search + filters, used for pagination).meta.unfilteredTotal- optional, number of rows before any search/filter.meta- optional extra information, e.g.filtersto populate select filter options.
parseResponse lets you adapt a different response shape. ArrayDataSource.fromUrl(url) fetches a static JSON file once and applies the query locally.
ArrayDataSource owns the whole collection in the browser and applies
filters/sort/pagination locally:
import { ArrayDataSource } from "data-grid-component/data-source";
const grid = new DataGrid({
columns: [{ field: "name", title: "Name" }],
dataSource: new ArrayDataSource([{ name: "Ada" }, { name: "Grace" }]),
});The server helpers (applyFilters, applySort, paginate, parseResult) are
exported from src/data-source.js and reused by demo/server.js so the client
and the server speak the same contract.
applySort always places empty values (null, undefined, empty string) at the
end of the page, whatever the direction. For FetchDataSource, the server
remains responsible for its own sort semantics.
When a request fails, the grid sets data-error, clears data-loading, fills
the empty-message area with the error (or the errorMessage option) and fires a
loadError event. The previous page is kept. A refresh() re-triggers the load.