Tabs
<k.Tabs> holds a list of tabs, each a group of blocks; the reader sees one
tab at a time. The first tab is open. Use it to split the same results by
grain or by view: a table by month in one tab, by week in another. With
param, the open tab is kept in the URL (?grain=month) and acts as an
input that When and the SQL can read; declare
it in page.filterParams with input: "tabs".
Example
monthly.sql and weekly.sql:
-- Sales per month
select '2026-01' as month, 410 as sales
union all select '2026-02', 455
-- Sales per week
select '2026-W05' as week, 98 as sales
union all select '2026-W06', 104
In report.tsx:
import monthly from "./monthly.sql?raw"
import weekly from "./weekly.sql?raw"
// in defineReport({ … })
page: {
filterParams: [
{
param: "grain",
label: "Grain",
input: "tabs",
options: () => [
{ value: "month", label: "By month" },
{ value: "week", label: "By week" },
],
},
],
},
queries: {
monthly: query<{ month: string; sales: number }>(monthly),
weekly: query<{ week: string; sales: number }>(weekly),
},
blocks: (k) => [
<k.Tabs
key="sales"
title="Sales"
param="grain"
tabs={[
{
label: "By month",
value: "month",
blocks: (
<k.Table
series="monthly"
columns={[{ key: "month", label: "Month", format: "month" }, { key: "sales", label: "Sales" }]}
/>
),
},
{
label: "By week",
value: "week",
blocks: (
<k.Table
series="weekly"
columns={[{ key: "week", label: "Week", format: "text" }, { key: "sales", label: "Sales" }]}
/>
),
},
]}
/>,
],
Props
A tab
A table inside a tab may leave out its title.
Checks
A tab without label or blocks, or a block inside it naming a series or
column the queries do not return, fails the typecheck.