Column Groups
.group(id, build) creates a structural group with stable child columns.
Use group() when the child columns are known at schema definition time and you want a structural scope for headers, selection, and formulas.
Groups also support condition: ({ ctx }) => boolean through the options object when the whole structural scope should be included or omitted from schema context.
Structural groups with .group()
group() receives a child builder and records a stable structural scope in the schema.
import { createExcelSchema } from "typed-xlsx";
type SalesRow = {
q1: number;
q2: number;
q3: number;
q4: number;
};
const schema = createExcelSchema<SalesRow>()
.group("quarters", { header: "Quarterly Revenue" }, (group) => {
group.column("q1", { header: "Q1", accessor: "q1" });
group.column("q2", { header: "Q2", accessor: "q2" });
group.column("q3", { header: "Q3", accessor: "q3" });
group.column("q4", { header: "Q4", accessor: "q4" });
})
.build();
Conditional structural groups
Use condition when a whole structural group should exist only for some schema-context configurations.
import { createExcelSchema, createWorkbook } from "typed-xlsx";
type Deal = { owner: string; amount: number; margin: number };
const schema = createExcelSchema<Deal, { showFinance: boolean }>()
.column("owner", { accessor: "owner" })
.group(
"finance",
{
header: "Finance",
condition: ({ ctx }) => ctx.showFinance,
},
(group) => {
group.column("amount", { accessor: "amount" });
group.column("margin", { accessor: "margin" });
},
)
.build();
createWorkbook()
.sheet("Deals")
.table("deals", {
rows: [],
schema,
context: { showFinance: true },
});
Groups work in both schema modes:
createExcelSchema<T>()/mode: "report"createExcelSchema<T>({ mode: "excel-table" })
In excel-table mode, the rendered headers still stay physically flat even when the schema contains structural groups.
Groups and formulas
Formula columns inside .group() follow the same predecessor-based rules as top-level formulas.
A formula declared inside a nested scope can reference:
- any column declared before the scope in the outer chain
- any column declared before it within the same group
Later formulas can aggregate the structural group with refs.group(...) and helpers like fx.sum(...) or fx.average(...).
import { createExcelSchema } from "typed-xlsx";
type Row = { baseRate: number; units: number };
const schema = createExcelSchema<Row>()
.column("baseRate", { accessor: "baseRate" })
.column("units", { accessor: "units" })
.group("derived", (group) => {
const withGrossRevenue = group.column("grossRevenue", {
header: "Gross",
formula: ({ row, refs, fx }) =>
fx.round(refs.column("units").mul(refs.column("baseRate")), 2),
style: { numFmt: "$#,##0.00" },
});
withGrossRevenue.column("commission", {
header: "Commission",
formula: ({ row, refs, fx }) => fx.round(refs.column("grossRevenue").mul(0.1), 2),
style: { numFmt: "$#,##0.00" },
});
})
.column("groupTotal", {
header: "Group Total",
formula: ({ refs, fx }) => fx.sum(refs.group("derived")),
style: { numFmt: "$#,##0.00", font: { bold: true } },
})
.build();
For the full scope rules and mode differences, see Scope & References.
For runtime-generated columns, see Dynamic Columns.