GroupedTable
<k.GroupedTable> draws lead columns (the period, the row's name), then the
same measures once per group, each group under its own header with a rule
before it. Use it when every row compares one set of measures across a few
categories: sales and orders per region, per month. Headers and cells are
small, to fit many columns.
Example
monthly.sql:
-- Sales and orders per month, for two regions
select '2026-01' as month, 120 as north_sales, 14 as north_orders, 95 as south_sales, 9 as south_orders, 0 as is_total
union all select '2026-02', 135, 15, 102, 10, 0
union all select 'Total', 255, 29, 197, 19, 1
In report.tsx:
import monthly from "./monthly.sql?raw"
type Row = {
month: string; north_sales: number; north_orders: number
south_sales: number; south_orders: number; is_total: number
}
// in defineReport({ … })
queries: { monthly: query<Row>(monthly) },
blocks: (k) => [
<k.GroupedTable
key="regions"
series="monthly"
title="Sales by region"
footer="is_total"
lead={[{ key: "month", label: "Month", format: "month" }]}
groups={[
{ label: "North", columns: [{ key: "north_sales", label: "Sales" }, { key: "north_orders", label: "Orders" }] },
{ label: "South", columns: [{ key: "south_sales", label: "Sales" }, { key: "south_orders", label: "Orders" }] },
]}
info={{ what: "Sales and orders per month in each region.", sql: ["monthly"] }}
/>,
],
The month format prints "2026-01" as "Jan 2026" and leaves "Total" as it
is.
Props
Also key, description, span (default 2) and info: see
Props every block takes.
A column in lead or a group takes the same keys as a
table column, except width.
A group
Checks
A series that is not one of the report's queries, or a column it names
that the query's rows do not have, fails the typecheck, as does a missing
required prop or a value of the wrong type.