Cell Styling
Every column accepts an optional style for data cells and a separate headerStyle for the header row. Both accept either a static CellStyle object or a callback that receives the current row and returns a CellStyle.
The CellStyle type
import type { CellStyle } from "@chronicstone/typed-xlsx";
const style: CellStyle = {
font: {
name: "Calibri",
size: 11,
bold: false,
italic: false,
underline: false,
strike: false,
color: { rgb: "000000" },
},
fill: {
color: { rgb: "FFFFFF" },
},
border: {
top: { style: "thin", color: { rgb: "CCCCCC" } },
right: { style: "thin", color: { rgb: "CCCCCC" } },
bottom: { style: "thin", color: { rgb: "CCCCCC" } },
left: { style: "thin", color: { rgb: "CCCCCC" } },
},
alignment: {
horizontal: "left",
vertical: "center",
wrapText: false,
},
numFmt: "General",
};
Every field is optional — pass only what you want to override.
Static styles
Static styles are applied to every data cell in the column regardless of row content.
import { createExcelSchema, type CellStyle } from "@chronicstone/typed-xlsx";
const moneyStyle: CellStyle = {
numFmt: "$#,##0.00",
alignment: { horizontal: "right" },
};
const dateStyle: CellStyle = {
numFmt: "dd/mm/yyyy",
alignment: { horizontal: "center" },
};
const schema = createExcelSchema<{ amount: number; createdAt: Date }>()
.column("amount", {
accessor: "amount",
style: moneyStyle,
})
.column("createdAt", {
accessor: "createdAt",
style: dateStyle,
})
.build();
Dynamic styles
Pass a function to compute the style from the row. The function receives (row, rowIndex, subRowIndex).
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();
Header styles
Use headerStyle to style the column header independently from its data cells.
import { createExcelSchema, type CellStyle } from "@chronicstone/typed-xlsx";
const darkHeader: CellStyle = {
fill: { color: { rgb: "1E3A5F" } },
font: { bold: true, color: { rgb: "FFFFFF" } },
alignment: { horizontal: "center" },
};
const schema = createExcelSchema<{ name: string; amount: number }>()
.column("name", { accessor: "name", headerStyle: darkHeader })
.column("amount", { accessor: "amount", headerStyle: darkHeader, style: { numFmt: "$#,##0.00" } })
.build();
Border styles reference
border.{top,right,bottom,left}.style accepts any of:
"thin" · "medium" · "thick" · "dashed" · "dotted" · "double" · "hair" · "dashDot" · "dashDotDot"
Number format strings
numFmt follows standard Excel format syntax. Common patterns:
| Format | Example output |
|---|---|
"#,##0" | 1,234 |
"#,##0.00" | 1,234.56 |
"$#,##0.00" | $1,234.56 |
"0%" | 75% |
"0.00%" | 75.00% |
"dd/mm/yyyy" | 31/12/2024 |
"d mmm yyyy" | 31 Dec 2024 |
"yyyy-mm-dd" | 2024-12-31 |
"hh:mm:ss" | 14:30:00 |
"#,##0.00\" €\"" | 1,234.56 € |
Column width
Width is set in character units alongside the style fields.
import { createExcelSchema } from "@chronicstone/typed-xlsx";
const schema = createExcelSchema<{ name: string; notes: string }>()
.column("name", { accessor: "name", width: 25 })
.column("notes", { accessor: "notes", width: 60, style: { alignment: { wrapText: true } } })
.build();
Use autoWidth: true to let the engine compute width from the column data. Combine minWidth and maxWidth to bound the auto-computed value.