Typed-xlsx
Schema Builder

Styling Overview

[object Object]

Styling in typed-xlsx now spans three different models. They share the same visual style vocabulary, but they run at different times and solve different problems.

The three styling models

Styling modelFieldEvaluated whenBest for
Base stylingstyle: CellStyleexport timeStable formatting such as number formats, alignment, fills, and borders
Build-time dynamic stylingstyle: (row, rowIndex, subRowIndex) => CellStyleexport timeStyling based on source row data known to JavaScript
Formula-based conditional stylingconditionalStyleinside Excel after openStyling that should react to formulas or later user edits

All three can coexist on the same column.

Mental model

  • style defines the base appearance of the data cell
  • style(row => ...) lets the export process choose a style from the source data
  • conditionalStyle emits native Excel conditional formatting rules that remain live in the workbook
  • headerStyle is separate and only affects the header row
  • table-level .table({ defaults }) can provide shared defaults for headers, summaries, and locked/unlocked/hidden cells

Important limitation:

  • conditionalStyle is visual only
  • it cannot configure worksheet protection (locked / hidden)
  • protection stays a regular cell style concern and only takes effect when the sheet itself is protected

For example:

import { 
createExcelSchema
} from "@chronicstone/typed-xlsx";
type
Deal
= {
amount
: number;
quota
: number;
status
: "open" | "won" | "at-risk";
}; const
schema
=
createExcelSchema
<
Deal
>()
.
column
("amount", {
accessor
: "amount",
style
: {
numFmt
: "$#,##0.00",
alignment
: {
horizontal
: "right" },
}, }) .
column
("quota", {
accessor
: "quota",
style
: {
numFmt
: "$#,##0.00",
alignment
: {
horizontal
: "right" },
}, }) .
column
("attainment", {
formula
: ({
row
,
fx
}) =>
fx
.
if
(
row
.
ref
("quota").
gt
(0),
row
.
ref
("amount").
div
(
row
.
ref
("quota")), 0),
style
: {
numFmt
: "0.0%",
alignment
: {
horizontal
: "right" },
},
conditionalStyle
: (
conditional
) =>
conditional
.
when
(({
row
}) =>
row
.
ref
("attainment").
lt
(0.5), {
fill
: {
color
: {
rgb
: "FEE2E2" } },
font
: {
color
: {
rgb
: "991B1B" },
bold
: true },
}), }) .
build
();

In that example:

  • the base number format and alignment come from style
  • the warning fill/font comes from conditionalStyle
  • Excel reevaluates the warning rule after the workbook opens

Summary cells are different

Summary cells now support styling too, but the exact capabilities depend on the summary kind:

  • reducer summaries support static style, dynamic style(value), and conditionalStyle
  • formula summaries support static style and conditionalStyle

That split exists because reducer summaries have a JavaScript-resolved final value during export, while formula summaries stay live in Excel.

Styling pages

Copyright © 2026 Cyprien Thao. Released under the MIT License.