Fields and pagination
Insert and update PAGE and NUMPAGES fields with explicit measured pagination and registered fonts.
A field stores an instruction and cached result text.
Reading a field does not execute its instruction.
You can insert and evaluate plain PAGE and NUMPAGES fields without switches.
The runtime preserves other instructions but rejects attempts to create or evaluate them.
Create a runtime with Runtime and setup.
Use context and document proxies inside runtime.run().
Insert a page field
Range.insertField(location, fieldType?, text?, removeFormatting?) returns Field.
It accepts Before, After, Start, End, or Replace.
Use Page or NumPages, or Empty with the text PAGE or NUMPAGES.
Omitting the type also requires supported instruction text.
The runtime rejects removeFormatting: true.
Resolve an anchor, insert the field, then update its result in a separate sync:
await runtime.run(async (context) => {
const paragraph = context.document.paragraphs.getLast();
paragraph.load('text');
await context.sync();
const anchor = paragraph.getRange('End');
await context.sync();
const field = anchor.insertField('After', 'NumPages');
await context.sync();
field.updateResult(); // Requires configured pagination on a server.
await context.sync();
});New fields start with an empty cached result.
Insertion does not calculate pagination.
Before and Start use the start endpoint; After and End use the end endpoint.
Replace requires an eligible span in one paragraph.
FieldType exports the Office.js-compatible field vocabulary.
FieldTypeLiteral provides corresponding string literals.
The presence of an enum value does not mean its instruction can run.
For example, FieldType.page is supported. The runtime rejects creation of fields outside the PAGE and NUMPAGES subset.
Read and change instructions
Body.fields and Range.fields return FieldCollection.
A range includes fields fully contained within that span.
Collections expose items, getFirst(), getLast(), getFirstOrNullObject(), and getLastOrNullObject().
Load each field's code before inspecting its raw instruction:
await runtime.run(async (context) => {
const fields = context.document.body.fields;
fields.load('items');
await context.sync();
for (const field of fields.items) field.load('code');
await context.sync();
console.log(fields.items.map((field) => field.code));
});Field.code = 'PAGE' or 'NUMPAGES' changes a supported page-field instruction.
It preserves the field identity and cached result until explicit evaluation.
Supported simple fields and ordinary complex fields with sibling runs can accept code changes.
The runtime rejects edits to protected fields, unsupported instructions, and edits made while tracking changes.
Field.delete() removes the field and its cached result through the supported deletion path.
Deleted field proxies become invalid.
Configure measured server pagination
Server result updates require CreateServerOptions.pagination.
ServerPaginationOptions contains a required measurer and optional producer.
Build the measurer from actual font resources using the core layout APIs.
The runnable report agent shows the complete font setup and cleanup:
bun examples/editor-api-consumers/report-agent.tsRun it from the repository root after installing workspace dependencies.
The example loads Carlito regular, bold, italic, and bold-italic files.
It registers those files explicitly as Calibri resources with sha256FontBytes and createLayoutShaping.
It builds createLayoutShapedMeasurer with a resolver that refuses unavailable requested faces.
Pass the configured measurer when opening the document:
const runtime = await DocxEditor.createServer(bytes, {
pagination: { measurer },
});Use the document's fonts or deliberately selected substitutes. Font substitution can change page breaks and page counts compared with Word. Bullets can request additional fonts, such as Symbol or Courier New. Provide those resources, or use an explicit registered font for custom Unicode bullets.
Dispose the runtime when the job finishes.
Release its shaping resources with disposeLayoutShaping(shaping) as the example shows.
A fixed-width test measurer does not establish production pagination fidelity.
A browser runtime uses its attached editor's layout.
Update results after document edits
Field.updateResult() computes cached text from measured pagination, including supported section page-number formats.
The computed result remains in the DOCX after saving and reopening.
Load the owning body's text after evaluation when you need the visible result.
The Field object exposes code, not a separate result property.
Multiple field result updates can share one sync, including fields in one paragraph. They can share queries, but cannot share other document writes. Finish text, table, picture, font, and page-layout edits first. Then evaluate fields in a separate transaction.
Updates fail with NotSupported if pagination is missing, the instruction is unsupported, or the cached result cannot be rewritten.
The server does not guess a page count or automatically resolve external field instructions.
On refusal, preserve the document and provide valid measurement resources or select an eligible field.
Next steps
See Page layout and stories and Batching, loading, and errors.