Schema Builder
Dynamic Styles
Compute export-time styles from the source row when styling depends on known data.
Pass a function to style when formatting depends on the source row at export time.
The function receives:
rowrowIndexsubRowIndex
This is the right model when JavaScript already knows the information needed to choose the style.
Row-dependent styling
import { createExcelSchema } from "@chronicstone/typed-xlsx";
type Order = {
status: "paid" | "pending" | "overdue";
amount: number;
};
const statusColors: Record<Order["status"], string> = {
paid: "166534",
pending: "A16207",
overdue: "B42318",
};
const schema = createExcelSchema<Order>()
.column("status", {
accessor: "status",
style: (row) => ({
font: {
bold: row.status === "overdue",
color: { rgb: statusColors[row.status] },
},
fill: {
color: { rgb: row.status === "overdue" ? "FEF2F2" : "FFFFFF" },
},
}),
})
.column("amount", {
accessor: "amount",
style: (row) => ({
numFmt: "$#,##0.00",
font: { bold: row.status === "overdue" },
}),
})
.build();
Sub-row-aware styling
When an accessor expands into sub-rows, subRowIndex lets the style function align with the physical row being emitted.
import { createExcelSchema } from "@chronicstone/typed-xlsx";
type Order = {
items: Array<{ qty: number; fulfilled: boolean; unitPrice: number }>;
};
const schema = createExcelSchema<Order>()
.column("qty", {
accessor: (row) => row.items.map((item) => item.qty),
})
.column("lineTotal", {
accessor: (row) => row.items.map((item) => item.qty * item.unitPrice),
style: (row, _rowIndex, subRowIndex) => {
const item = row.items[subRowIndex];
return {
numFmt: "$#,##0.00",
font: {
color: { rgb: item?.fulfilled ? "166534" : "B42318" },
},
};
},
})
.build();
Use dynamic styles when
Use style: (row) => ... when:
- the styling decision is already known during export
- you want full JavaScript freedom
- the workbook does not need to keep reevaluating the style after open
If the style should remain live in Excel and react to formulas or user edits, use Conditional Styles instead.