typed-xlsx
Core Concepts

Schema Context

Understand schema-wide context, where ctx is available, and why context is required independently from selection.

createExcelSchema<Row, Context>() declares a schema-wide runtime context object.

That object is part of the schema contract. It is not tied to one feature and it is not only for dynamic(...).

What schema context is for

Schema context is useful when some export-time inputs are known outside the row itself, such as:

  • region or territory lists
  • reporting periods
  • currency or locale preferences
  • feature flags or presentation options
  • lookup maps used by formulas, styles, or hyperlinks

Anywhere the API exposes ctx, it is the same schema-level object.

Where ctx is available

ctx flows from the table-level context option into every callback that receives it:

mermaid
flowchart LR
  T["table(…, { context })"]
  T --> D["dynamic()"]
  T --> C["condition"]
  T --> A["accessor"]
  T --> TR["transform"]
  T --> F["format"]
  T --> S["style"]
  T --> H["hyperlink"]
  T --> FX["formula"]

Depending on the callback type, ctx can be used in:

  • condition
  • dynamic(...)
  • accessor callbacks
  • transform
  • format
  • style
  • hyperlink
  • formula callbacks
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", {
accessor
: "amount",
format
: ({
ctx
}) => `${
ctx
.
currencySymbol
}#,##0.00`,
style
: ({
row
,
ctx
}) => ({
font
: {
bold
:
row
.
region
===
ctx
.
featuredRegion
,
}, }), }) .
build
();

Context is required per contextful schema

If a schema declares createExcelSchema<Row, Context>(), tables built from that schema must provide context.

This is true even when select excludes all dynamic scopes, because context belongs to the schema as a whole.

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", {
No overload matches this call. Overload 1 of 2, '(id: string, input: WorkbookReportTableOptions<SchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, any>, { readonly exclude: readonly ["memberships"]; }>): WorkbookSheet', gave the following error. Argument of type '{ rows: never[]; schema: SchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, any>; select: { exclude: ["memberships"]; }; }' is not assignable to parameter of type 'WorkbookReportTableOptions<SchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, any>, { readonly exclude: readonly ["memberships"]; }>'. Property 'context' is missing in type '{ rows: never[]; schema: SchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, any>; select: { exclude: ["memberships"]; }; }' but required in type '{ context: { orgIds: number[]; }; }'. Overload 2 of 2, '(id: string, input: WorkbookExcelTableOptions<SchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, any>, { readonly exclude: readonly ["memberships"]; }>): WorkbookSheet', gave the following error. Argument of type '{ rows: never[]; schema: SchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, any>; select: { exclude: ["memberships"]; }; }' is not assignable to parameter of type 'WorkbookExcelTableOptions<SchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, any>, { readonly exclude: readonly ["memberships"]; }>'. Property 'context' is missing in type '{ rows: never[]; schema: SchemaDefinition<Row, "name", never, "memberships", { orgIds: number[]; }, any>; select: { exclude: ["memberships"]; }; }' but required in type '{ context: { orgIds: number[]; }; }'.
rows
: [],
schema
,
select
: {
exclude
: ["memberships"] },
});

Context shape is fully typed

Use SchemaContextOf<typeof schema> when you want to extract the required table-time context shape from a built schema.

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.