typed-xlsx
Core Concepts

Schema Context

Pass export-time inputs such as regions, locale or feature flags into a schema, and use them in columns, formulas, styles and labels.

Some inputs aren't part of a row: the regions to show, the reporting period, the currency, the locale, a feature flag. Declare them as the schema's context, and every table built from that schema must pass them in.

createExcelSchema<Row, Context>();

The same ctx object reaches every callback that accepts it:

WhereExample
dynamic() buildersone column per region in ctx.regions
conditioninclude a column only when ctx.showFinance is true
accessors, transform, formatconvert with ctx.fxRate, format with ctx.currency
style, badge label callbackshighlight ctx.featuredRegion
hyperlinkbuild URLs from ctx.baseUrl
formulareference a rate passed at export time
titles, headers, group headers, summary and totals labels, validation messages, link tooltipstranslate with ctx.t(key)

Declare it and use it

import { 
createExcelSchema
} from "typed-xlsx";
type
Deal
= {
amount
: number;
region
: "EMEA" | "AMER" | "APAC";
}; type
SchemaContext
= {
featuredRegion
:
Deal
["region"];
currencySymbol
: string;
}; const
schema
=
createExcelSchema
<
Deal
,
SchemaContext
>()
.
column
("regionOnly", {
accessor
: "region",
condition
: ({
ctx
}) =>
ctx
.
featuredRegion
=== "EMEA",
}) .
column
("amount", {
header
: ({
ctx
}) => `${
ctx
.
currencySymbol
} amount`,
accessor
: "amount",
format
: ({
ctx
}) => `${
ctx
.
currencySymbol
}#,##0.00`,
style
: ({
row
,
ctx
}) => ({
font
: {
bold
:
row
.
region
===
ctx
.
featuredRegion
,
}, }), }) .
build
();

Text callbacks run when the table receives its context, so one schema can serve several locales:

import { 
createExcelSchema
,
createWorkbook
} from "typed-xlsx";
type
Row
= {
status
: string };
type
Context
= {
t
(
key
: string): string };
const
schema
=
createExcelSchema
<
Row
,
Context
>()
.
column
("status", {
accessor
: "status",
header
: ({
ctx
}) =>
ctx
.
t
("columns.status"),
summary
: (
summary
) => [
summary
.
label
(({
ctx
}) =>
ctx
.
t
("totals.label"))],
}) .
build
();
createWorkbook
()
.
sheet
("Exports")
.
table
("statuses", {
context
: {
t
: (
key
) =>
key
},
rows
: [],
schema
,
title
: ({
ctx
}) =>
ctx
.
t
("reports.statuses.title"),
});

Every table must pass the context

If a schema declares a context type, every table built from it must provide context, even when select leaves out the columns that use it. The context belongs to the schema as a whole, so the check doesn't depend on the selection:

import { 
createExcelSchema
,
createWorkbook
} from "typed-xlsx";
type
Row
= {
name
: string;
orgs
: number[] };
const
schema
=
createExcelSchema
<
Row
, {
orgIds
: number[] }>()
.
column
("name", {
accessor
: "name" })
.
dynamic
("memberships", (
builder
, {
ctx
}) => {
for (const
id
of
ctx
.
orgIds
) {
builder
.
column
(`org-${
id
}`, {
accessor
: (
row
) =>
row
.
orgs
.
includes
(
id
) });
} }) .
build
();
createWorkbook
()
.
sheet
("Sheet")
.
table
("sheet", {
Argument of type '{ rows: never[]; schema: ReportSchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, WithColumnValue<EmptyColumnValues, "name", string>>; select: { ...; }; }' is not assignable to parameter of type 'WorkbookReportTableOptions<ReportSchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, WithColumnValue<EmptyColumnValues, "name", string>>, { ...; }> & ValidateKeys<...> & { ...; }'. Type '{ rows: never[]; schema: ReportSchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, WithColumnValue<EmptyColumnValues, "name", string>>; select: { ...; }; }' is not assignable to type 'WorkbookReportTableInput<ReportSchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, WithColumnValue<EmptyColumnValues, "name", string>>, { ...; }> & { ...; } & ValidateKeys<...> & { ...; }'. Property 'context' is missing in type '{ rows: never[]; schema: ReportSchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, WithColumnValue<EmptyColumnValues, "name", string>>; select: { ...; }; }' but required in type '{ context: { orgIds: number[]; } | undefined; }'.
rows
: [],
schema
,
select
: {
exclude
: ["memberships"] },
});

Get the context type from a schema

SchemaContextOf<typeof schema> extracts the context a built schema requires, for example to type a function that prepares it:

import { 
createExcelSchema
} from "typed-xlsx";
import type {
SchemaContextOf
} from "typed-xlsx";
const
schema
=
createExcelSchema
<{
name
: string }, {
locale
: string }>()
.
column
("name", {
accessor
: "name" })
.
build
();
type
RequiredContext
=
SchemaContextOf
<typeof
schema
>;
Copyright © 2026 Cyprien Thao. Released under the MIT License.