Server grouping
Grouping on the server: one group path at a time, what the server owns and what the grid owns.
@workspace/active-grid 11.0.0Status unknowncontent differs from the recorded release 11.0.0baseline ce081dc3
This guide is the package's docs/, included
unchanged from the package as it is in Foundation. Links to the package's
internal design documents keep their text.
Server grouping fetches one group path at a time. The server owns group membership, authorization, query execution and aggregate values. The grid owns expansion controls, loading state, cached children and synthetic display rows. Client grouping instead runs in the kernel over loaded source records.
Enabling#
Use the resource-backed fetch adapter and server-declared capabilities from
Resource-backed server mode. Grouping must be enabled
both for the grid and for its server mode. This fragment assumes the host
supplies fetch, capabilities, columns and the reader's locale:
<ActiveGrid gridId="orders-by-region" locale={locale} mode="server" fetchFn={fetchOrders} serverCapabilities={capabilities} columns={columns} enableGrouping enableServerGrouping serverGroupBy={[{field: 'region', sort: 'asc'}, {field: 'category'}]}/>server is an ordered Group, not an array of strings.
The server capability map determines which fields may be grouped and aggregated.
Do not configure the removed server component prop.
How requests look#
The grouping hook calls fetch with the ordinary Server
(page, fetch, sorting, filters, global, signal)
plus:
group: orderedBy {field, sort?}declarations;group: the path being fetched;Keys []means top level,['Europe']means children of that region.
There is no expanded request field. Expansion state stays in the
outer hook; each fetch asks for one path. The optional historical
group wire field remains declared but the grid does not populate
it. Resource aggregation policy belongs to the server resource declaration.
fetch is a fetch-block size, distinct from the visible page size. A
resource group listing returns its complete permitted group listing or refuses
it according to the server's grouping limits; it is not a silently truncated
leaf page. Leaf requests use paging. See Server mode.
Grouped response#
A fetch resolves to Paged, not an action envelope containing
rows. The resource adapter unwraps its action response. For grouped results,
is and groups: Group describe the groups. For example:
import type {GroupInfo} from '@workspace/active-grid';
const groups: GroupInfo[] = [ { key: 'Europe', count: 42, aggregations: {amount: 1250}, hasSubGroups: true, },];Paged remains the response data field; total is the
count for the requested level. For a leaf result, return its records in
data without grouped metadata. The server revalidates the grouping path,
filters and sorting and applies its own authorization at every level.
Synthetic display rows#
The grouping hook constructs a Server from each Group:
__, __, __, __, optional
__ / __, __ and __.
These markers describe the outer server-grouping representation. They are
separate from the kernel's client-generated Generated union member.
Each synthetic row is a row of the grid for assistive technology too: it
carries the same logical aria- as the rows around it, so group rows,
loaded records and load-more rows form one unbroken sequence, also in the
mounted window of a virtualized body.
Use is to narrow a server marker and
is for a load-more marker. The outer owner supplies
synthetic IDs before the domain row-ID callback; that callback remains about
real records. Do not pretend a synthetic group is an ordinary domain record.
Load-more rows#
When loaded children do not reach the level's total, the hook creates a
Server with __, __,
__, __ and __. Activating it fetches the next
block for that path and appends the accepted children. The server returns
records and counts; it does not need to manufacture this UI marker. A
load-more row stands under a leaf group only.
The row is a row of the grid's keyboard navigation. The arrow keys reach it,
and Enter or Space on any of its cells activates it; a click does the same,
through the same action. It is named by its label ("10 of 42 loaded (load
more)"), its cells carry aria-, and while the block
is loading the row is aria- and a second activation asks for nothing.
When the block lands, the active cell keeps its display position, which now
holds the first new row; see Keyboard.
Rendering aggregations#
Group metadata's aggregations map becomes __ on the
synthetic display row. Keys correspond to column IDs. The server-declared
aggregate capability and column presentation semantics determine the display.
A source-record formatter must not be called with a made-up group record;
see the callback contract in Columns. Client grouping
separately requires a declared aggregation (DC-3).
State persistence#
Server-group expansion is local React state in the grouping hook. It is not
persisted to localStorage or the URL. This differs from the kernel's client
expanded slice. The URL owns only page, page, sort, filters
and search; see URL state.
Performance#
Loaded group children can be reused while their cache entry remains valid. Sorting, filtering, global search and grouping changes invalidate the grouping dataset and collapse its local expansion state. Explicit refresh and cache eviction also prevent a blanket promise of zero refetches. Load-more keeps leaf fetches bounded; the grid does not load the entire leaf dataset to group it.
Reference#
Current architecture: kernel and outer ownership.
Server contract: client declarations and hydration.
Resource-backed server mode: supported server adapter.
E2E harness: current grouping fixture navigation.