Classes
CssGenerator
class CssGenerator
Translates resolved WordprocessingML properties into CSS declarations.
Runs after style resolution, never during parsing. Keeping the two apart is
what makes it possible to lay the same document out at different zoom levels,
to export it without a DOM, and to fix a rendering bug without touching the
parser.
Declarations are emitted as shared classes through a {@link StyleSheetBuilder}
rather than as inline styles. In a document with 200 000 runs the difference
is roughly 200 000 style attributes versus about fifty CSS rules, which shows
up directly in style recalculation time and in memory.
runClass
(properties: RunProperties) => string | undefined
Returns the CSS class implementing a resolved run format.
paragraphFontClass
(properties: ParagraphProperties, smallestRunHalfPoints?: number, runFontFamily?: string) => string | undefined
Returns a class carrying the paragraph's baseline font.
A paragraph style contributes run properties, and those form the default for
every run inside it. Placing the font and size on the paragraph element
makes relative units resolve correctly and lets runs that match the default
carry no class of their own.
paragraphClass
(properties: ParagraphProperties, runFontFamily?: string, gridPitchTwips?: number, runSizeHalfPoints?: number, eastAsianText?: boolean, runFonts?: readonly RunFont[]) => string | undefined
Returns the CSS class implementing a resolved paragraph format.
runDeclarations
(properties: RunProperties) => Record<string, string | undefined>
Builds the declaration map for run formatting.
paragraphDeclarations
(properties: ParagraphProperties, runFontFamily?: string, gridPitchTwips?: number, runSizeHalfPoints?: number, eastAsianText?: boolean, runFonts?: readonly RunFont[]) => Record<string, string | undefined>
Builds the declaration map for paragraph formatting.
cellDeclarations
(properties: CellProperties, defaultMargins?: CellProperties["margins"]) => Record<string, string | undefined>
Builds the declaration map for a table cell.
rowDeclarations
(properties: RowProperties, rulePoints?: number, cellMarginPoints?: number) => Record<string, string | undefined>
Builds the declaration map for a table row.
DocxView
class DocxView extends BaseDocumentView<DocxDocument>
Renders a Word document as paginated, virtualised pages.
The pipeline runs in three stages that are deliberately kept apart:
rendering turns the model into DOM without knowing about pages, the layout
engine measures that DOM and decides where pages break, and the virtualiser
decides which of those pages exist in the document at any moment. Because the
stages do not know about each other, changing the zoom re-runs only layout,
and scrolling re-runs only virtualisation.
layout
LayoutResult | undefined
The current pagination, once layout has completed.
currentPage
number
Index of the page nearest the top of the viewport.
goToPage
(index: number, behavior?: ScrollBehavior) => void
Scrolls to a page, mounting it first.
mountAllPages
() => void
Fills in every page, undoing virtualisation for the whole document.
Wanted whenever something other than a reader looks at the document: the
print pipeline, a full-document export, a comparison against a reference.
Costly by design — it is the memory virtualisation exists to avoid — so it
is never done on the reader's behalf except when printing.
resumeVirtualisation
() => void
Hands the document back to the virtualiser after `mountAllPages`.
Until this is called every page stays in the DOM, which is the point — but
also the whole cost virtualisation exists to avoid, so a caller that only
needed the document whole for a moment should say when the moment has
passed.
goToBookmark
(name: string, behavior?: ScrollBehavior) => boolean
Scrolls to the page a bookmark landed on.
renderContent
() => Promise<void>
Renders the content into {@link root}. Called on every update.
onContainerResize
() => void
Resizing the container does not re-paginate.
A page's text area comes from the section — page size minus margins — and
content is measured against that width, never against the container. So a
resize cannot move a single page break, and re-running layout on one is not
merely wasted work: it is a feedback loop. Pagination replaces the page
elements, which removes the scrollbar, which widens the container, which
triggers another resize; the document flickers continuously and the reader's
scroll position is thrown away each time.
Zoom is the only thing that changes page geometry, and it goes through
`setZoom`.
setZoom
(zoom: number) => void
Changes the zoom level and re-renders.
update
() => void
Re-render after the container was resized or settings changed.
destroy
() => void
Tear the view down and release resources. The container is left empty.
LayoutEngine
class LayoutEngine
Paginates a document by measuring its rendered content.
Word does not store pages; it stores a flow, and where the pages fall depends
on the fonts available, the printable area and the line-breaking of the
renderer. Viewers usually sidestep this by trusting Word's cached
`lastRenderedPageBreak` hints, which reproduces the pagination of whatever
machine last opened the file and silently disagrees with what the reader now
sees. This engine measures the content as it will actually be displayed and
breaks accordingly.
Three properties make it viable on very large documents:
- Blocks are flowed in chunks, so a chunk costs one forced layout rather than
one per block.
- The main thread is released between pages, so a 2000-page document
paginates without freezing the page and can report progress.
- Finished pages leave the measuring frame immediately, so peak memory is
proportional to a page, not to the document.
paginate
(blocks: readonly BlockNode[], finalSection: SectionProperties, host: HTMLElement, options: LayoutOptions) => Promise<LayoutResult>
Lays the document out into pages.
Blocks are flowed into a frame exactly as wide as the text column and the
browser is asked where they landed, rather than being measured one at a time
and added up. The difference matters for anything whose height is not its
own: a floated picture contributes nothing to the block that holds it and
narrows the blocks after it, so a sum of block heights describes a page that
does not exist. Positions in a real flow describe the page that does.
The frame holds only what has not yet been assigned to a page. Once a page
is decided its blocks are taken out, and the remainder re-flows from the top
— which is precisely what a new page is: a fresh region, with the floats of
the previous page gone. Each block therefore enters and leaves the frame
once, so the cost stays linear in the document.
PageVirtualizer
class PageVirtualizer
Mounts only the pages near the viewport.
This is what makes very large documents usable. A 1500-page document contains
on the order of a million DOM nodes; creating them all costs seconds of layout
and hundreds of megabytes, and the browser then repeats that work on every
resize. Here each page is a fixed-size box from the start — the layout engine
already knows every page's dimensions — so the scrollbar is correct
immediately and the content of a page is created only when it approaches the
viewport and discarded once it leaves.
Because page geometry never depends on the mounted content, mounting and
unmounting cannot shift the scroll position, which is the failure mode that
makes naive virtualisation jitter.
Visibility is decided from geometry in one place, and `IntersectionObserver`
and `scroll` merely signal that a recalculation is due. Relying on the
observer alone is tempting but fragile: it interacts badly with
`content-visibility`, is silently unavailable in some embedded contexts, and
when it fails it fails invisibly — the document simply stops rendering pages.
Recomputing from rectangles is cheap enough to be the source of truth.
addPage
(page: PageLayout, pageElement: HTMLElement) => void
Registers a page and its fixed-size container.
start
(scrollParent?: HTMLElement) => void
Starts observing visibility. Call after every page has been added.
ensureMounted
(index: number) => void
Mounts a page immediately, e.g. before scrolling to it programmatically.
mountAll
() => void
Mounts every page.
Printing needs this: the browser paginates the document as it stands, and a
virtualised document stands as a few real pages between hundreds of empty
boxes — which is exactly what would come out of the printer. Anything else
that has to see the whole document at once, such as a full-text search or a
comparison against a reference rendering, needs it for the same reason.
resume
() => void
Lets the virtualiser start releasing pages again.
The counterpart of `mountAll`, and the caller's responsibility: a document
left pinned holds every page of DOM it ever built, which is the cost
virtualisation exists to avoid.
visiblePageIndex
() => number
Index of the page currently closest to the top of the viewport.
scrollToPage
(index: number, behavior?: ScrollBehavior) => void
Scrolls a page into view, mounting it first so the target is real.
scrollParent
HTMLElement | undefined
The element whose scrolling drives visibility; `undefined` for the window.
pageElement
(index: number) => HTMLElement | undefined
ThemeResolver
class ThemeResolver
Resolves theme colour and font references into concrete values.
Word rarely writes a literal colour. It writes "accent1, 40% lighter", encoded
as a theme slot plus `themeTint`/`themeShade` modifiers, and the actual RGB
lives in `theme1.xml`. A viewer that reads only `w:color/@w:val` renders every
themed document in black, which is the single most visible difference between
a correct DOCX renderer and an approximate one.
runColor
(properties: RunProperties) => string | undefined
Resolves the effective text colour of a run.
`w:color/@w:val` wins when it is a literal; otherwise the theme slot is
looked up and the tint or shade modifier applied.
themeColor
(slot: string, tintHex?: string, shadeHex?: string) => string | undefined
Resolves a theme colour slot with optional tint or shade.
drawingThemeColor
(slot: string, lumMod?: number, lumOff?: number) => string | undefined
Resolves a DrawingML theme colour with luminance modulation.
DrawingML expresses variations as `lumMod`/`lumOff` in thousandths of a
percent rather than as the tint/shade bytes used by WordprocessingML.
drawingColor
(reference: ColorReference | undefined) => string | undefined
Resolves a DrawingML colour reference, modifiers and all.
A shape's colour is almost never a literal. It is a theme slot with a stack
of modifiers on it — `accent1` at 60% luminance with a 40% offset is the
pale panel behind a cover headline, and `accent1` with `shade 50000` is the
dark one under it. Resolving the slot and dropping the stack paints both of
them the same saturated accent, which is worse than the right colour and
more obvious than none.
The order is DrawingML's: shade and tint act on the colour, then the
luminance modulation, then alpha turns it translucent.
drawingRgba
(reference: ColorReference | undefined) => Rgba | undefined
The same, as a colour rather than as CSS, for callers that must compare it.
themeFont
(slot: string) => string | undefined
Resolves a theme font slot such as `minorHAnsi` to a font family name.
Word writes `w:asciiTheme="minorHAnsi"` instead of a family name so the
document follows the theme; without resolution every run falls back to the
browser default.
cssVariables
() => Record<string, string>
CSS custom properties exposing the theme to stylesheets and to the host app.
Functions
baseStyles
function baseStyles(prefix: string): string
Base stylesheet of the DOCX renderer.
Only structural rules live here: the sheet of paper, the page frame, table
defaults, and the small amount of chrome the viewer adds. Everything derived
from the document itself is emitted as generated classes, so this file never
needs to change when format support grows.
breakLinesIn
function breakLinesIn(root: HTMLElement, metrics: TextMetricsCache, stats?: LineBreakStats, obstacles?: readonly DOMRect[]): void
Breaks every paragraph of a subtree that can be broken here.
breakParagraph
function breakParagraph(paragraph: HTMLElement, metrics: TextMetricsCache, stats?: LineBreakStats, obstacles?: readonly DOMRect[]): boolean
Breaks one paragraph into explicit lines.
Returns whether it did. The paragraph must already be laid out: the width it
is broken to is the width the browser gave it, which for a cell of an
automatically sized table cannot be known any other way.
createLayoutProfile
function createLayoutProfile(): LayoutProfile
A profile with every counter at zero, ready to be filled.
createPageElement
function createPageElement(ownerDocument: Document, classPrefix: string, width: number, height: number, index: number): HTMLElement
Creates the fixed-size container of a page.
The dimensions come from the section, not from the content, which is what
lets the scrollbar be correct before any page has been mounted.
floatObstacles
function floatObstacles(frame: HTMLElement): DOMRect[]
The boxes text has to flow around, in viewport coordinates.
A float narrows the *line boxes* beside it and not the block that holds them,
so a paragraph standing next to a picture has the full width of the column and
lines that are considerably shorter. Nothing about the paragraph itself says
so, which is why the obstacles have to be found from outside and passed in.
pageGeometry
function pageGeometry(section: SectionProperties, zoom: number, insets?: PageInsets, mirrored?: boolean): { pageWidth: number; pageHeight: number; contentWidth: number; contentHeight: number; contentTop: number; contentBottom: number; marginTop: number; marginRight: number; marginBottom: number; marginLeft: number; headerOffset: number; footerOffset: number; columnCount: number; columnGap: number; columnWidth: number; flowHeight: number; }
Measured heights of the running head and foot, applied to the page box.
A header is not confined to the top margin: it starts at the header offset and
grows downward, and when it outgrows the margin Word moves the body text down
to clear it rather than letting the two overlap.
quoteFont
function quoteFont(name: string): string
Quotes a font family name when it needs it, so CSS stays valid.
renderBlock
function renderBlock(context: RenderContext, block: BlockNode, section?: SectionProperties, tableContext?: TableStyleContext, neighbours?: Neighbours): HTMLElement | undefined
Renders a single block.
renderBlocks
function renderBlocks(context: RenderContext, blocks: readonly BlockNode[], container: HTMLElement, section?: SectionProperties, tableContext?: TableStyleContext): void
Renders a list of blocks into a container.
renderInlineNodes
function renderInlineNodes(context: RenderContext, nodes: readonly InlineNode[], container: HTMLElement, paragraphStyleId?: string, tableContext?: TableStyleContext): void
Renders inline content into a container.
The renderer emits one `<span>` per formatting run rather than per source run:
consecutive runs that resolve to the same formatting are merged, which is a
large win on documents produced by Word, where a single sentence is routinely
split into a dozen runs by spell-check state and revision ids that have no
visual effect.
renderMath
function renderMath(ownerDocument: Document, node: MathNode): Element
Renders an OMML expression as MathML.
MathML is the right target: every current browser renders it natively, it
stays selectable and searchable, it scales with the surrounding text, and it
needs no external library. The alternative approaches — rasterising equations,
or shipping a full TeX layout engine — either lose the text or add megabytes
to the bundle for a feature most documents use sparingly.
The mapping covers the constructs Word actually produces. Anything unmapped
degrades to its concatenated text rather than disappearing, so an unsupported
construct still shows its symbols.
renderParagraph
function renderParagraph(context: RenderContext, node: ParagraphNode, tableContext?: TableStyleContext, neighbours?: Neighbours, section?: SectionProperties): HTMLElement
Renders a paragraph.
Headings are emitted as `h1`..`h6` so the document has real structure for
screen readers and for the browser's own outline, rather than a wall of
visually-styled `div`s.
renderTable
function renderTable(context: RenderContext, node: TableNode, section?: SectionProperties): HTMLElement
Renders a table.
Real tables, not a grid of divs: `<table>` gives correct column sizing, cell
merging through `rowspan`/`colspan`, and accessible semantics for free, and
the browser's table layout algorithm is closer to Word's than anything that
could reasonably be reimplemented.
splitAtOffset
function splitAtOffset(element: HTMLElement, offset: number): SplitResult | undefined
Cuts an element into two at a global text offset.
The element is cloned twice and the text on the wrong side of the cut removed
from each copy, which preserves the full ancestor chain of every run: a split
in the middle of bold text must leave bold text on both pages.
splitIntoSections
function splitIntoSections(blocks: readonly BlockNode[], finalSection: SectionProperties): DocumentSection[]
Splits the body into sections.
Section properties live on the *last* paragraph of the section they describe,
with the final section's properties on the body itself. Reading them as if
they applied forwards puts every page setup one section out of place.
splitParagraph
function splitParagraph(element: HTMLElement, availableHeight: number, minLines?: number): SplitResult | undefined
Splits a paragraph element so that its first part fits into `availableHeight`.
Returns `undefined` when no useful split exists: the element has a single
line, or not even one line fits, in which case the caller moves it whole.
splitTable
function splitTable(table: HTMLTableElement, availableHeight: number, minRows?: number, pageHeight?: number): SplitResult | undefined
Splits a table across a page boundary.
Whole rows first, because that is where Word breaks whenever it can. But a
row is not an indivisible unit, and treating it as one is not a small
simplification: a row taller than the text area can then never be broken, so
it goes on one page in its entirety and overflows it. The minutes of a
committee — a two-column table whose right column runs for pages — comes out
with the whole debate on one sheet and three empty ones after it. Measured on
such a document: Word 28, 39, 37, 37, 25 lines per page, ours 16, 2, 100, 37,
2.
So a row that cannot fit is divided through its cells, which is what Word
does: the cell borders are left open at the boundary and the row continues on
the next page. `w:cantSplit` is what forbids it, and the caller checks that.
Interfaces
DocumentSection
interface DocumentSection
A section of the document, together with the blocks that belong to it.
startBlock
number
Index of the first block of the section in the flattened body.
endBlock
number
Index one past the last block of the section.
DocxRenderOptions
interface DocxRenderOptions
Options that control what the renderer produces.
renderHeaders?
boolean | undefined
Render headers and footers. Defaults to true.
renderFootnotes?
boolean | undefined
Render footnotes at the bottom of the page they are referenced from.
renderEndnotes?
boolean | undefined
Render endnotes after the final page.
renderComments?
boolean | undefined
Show comments in a margin column. Defaults to false.
renderTrackedChanges?
boolean | undefined
Show tracked changes as insertions and deletions. Defaults to false.
paginate?
boolean | undefined
Paginate the document.
When false the content is rendered as one continuous flow, which is faster
and appropriate for embedding a document into a page. Defaults to true.
classPrefix?
string | undefined
Class name prefix for every generated element and rule.
zoom?
number | undefined
Rendering scale, 1 means 100%.
rtl?
boolean | undefined
Treat the document as right-to-left regardless of its own setting.
lineBreaking?
"browser" | "own" | undefined
Who decides where a line of text ends.
`browser` hands the text to CSS and measures what came back, which is what
this viewer has always done. `own` breaks the lines here, from the font's own
advances and by Word's rules, and writes each one back as a block of its own
— see `layout/line-breaker.ts`. Defaults to `browser`.
DocxViewOptions
interface DocxViewOptions extends ViewOptions, DocxRenderOptions
scrollParent?
HTMLElement | undefined
Element that scrolls; defaults to the container.
onLayoutProgress?
((fraction: number) => void) | undefined
Called when pagination progresses, with a fraction between 0 and 1.
onLayoutComplete?
((result: LayoutResult) => void) | undefined
Called once pagination completes.
onPageChange?
((pageIndex: number) => void) | undefined
Called when the visible page changes.
traceLayout?
LayoutTraceEntry[] | undefined
Collects a record of why each page ended, into the array supplied.
For diagnostics: the pagination tools read it to say *why* a page holds
what it holds, which nothing else in the pipeline can answer.
profile?
LayoutProfile | undefined
Collects how long each stage of a layout pass took.
For the same reason as `traceLayout`, and answering the other half of the
question: that one says why a page ended, this one says what it cost.
LayoutOptions
interface LayoutOptions
Options controlling pagination.
zoom
number
Rendering scale; affects measurement and therefore where pages break.
batchSize?
number | undefined
Number of blocks measured per batch.
Measurement forces a synchronous layout, so blocks are appended in batches
and read back in one pass: 200 blocks cost one reflow instead of 200.
Larger batches are faster overall but hold the main thread longer.
splitParagraphs?
boolean | undefined
Split paragraphs across page boundaries.
When off, a paragraph that does not fit moves to the next page whole, which
is faster but leaves ragged pages. On by default.
onProgress?
((fraction: number) => void) | undefined
Called as pagination progresses, with a fraction between 0 and 1.
signal?
AbortSignal | undefined
Aborts a long pagination run.
trace?
LayoutTraceEntry[] | undefined
Collects a record of why each page ended.
Off unless an array is supplied: the entries are cheap but the question is
only ever asked by a diagnostic.
onBeforeMeasure?
(() => void) | undefined
Called after a batch has been rendered but before it is measured.
Rendering generates the CSS classes the content needs, and those rules have
to be in the document before heights are read: measuring unstyled content
would put every page break in the wrong place. The view uses this hook to
flush its stylesheet.
insets?
PageInsets | undefined
Measured header and footer heights, which shrink the text area when they
outgrow their margins. See `PageInsets`.
insetsFor?
((section: SectionProperties, firstOfSection: boolean, displayNumber: number) => PageInsets) | undefined
The insets of one particular page, when they differ from page to page.
Word gives every page the text area its own running head leaves it, and a
document with a title page gives that page a different head from the rest —
which is what `w:titlePg` is for, and what a quarter of the documents that
have headers at all do. Reserving the tallest head on every page costs the
others the difference, and a page short of a line's worth of room spills a
line, and the document ends up a page long.
The caller resolves it, because which head a page shows depends on document
settings the layout engine has no business knowing.
profile?
LayoutProfile | undefined
Collects how long each half of pagination took.
Off unless an object is supplied. See `LayoutProfile`.
LayoutProfile
interface LayoutProfile
Where the time of a layout pass went, in milliseconds.
Quality has never been the only axis: a rule that gains a page of fidelity
and doubles the time is a different answer from one that gains it for free,
and until this existed the corpus run could not tell the two apart — it timed
the whole run and nothing inside it.
The split is the one the pipeline already has. `renderMs` is turning the
model into DOM, which is our own code; `paginateMs` less `renderMs` is asking
the browser where everything landed, which is the browser's. A change that
moves the second without moving the first has changed how much layout we ask
for, not how much work we do.
Recorded only when asked for, so a reader pays nothing.
renderMs
number
Turning blocks into DOM: `renderBlock` and everything under it.
paginateMs
number
The whole pagination pass, rendering included.
insetsMs
number
Measuring the running parts, which has to happen before any break.
buildMs
number
Building the page shells and handing them to the virtualiser.
breakMs
number
Breaking paragraphs into lines here rather than in the browser, and how
much of the document that path could take. Zero on the browser path.
skippedByReason
Record<string, number>
Why the paragraphs that fell back to the browser did.
LayoutResult
interface LayoutResult
Result of laying out a document.
bookmarkPages
ReadonlyMap<string, number>
Bookmark name → page index, used to resolve `PAGEREF` fields.
sectionPageCounts
readonly number[]
Page index of each section's last page, used by `SECTIONPAGES`.
trace?
readonly LayoutTraceEntry[] | undefined
Why each page ended, when the caller asked to be told.
LayoutTraceEntry
interface LayoutTraceEntry
Why one page came out the way it did.
The line report can say a page holds the wrong content; it can never say
*why*, and the answer is almost always one of a handful of decisions the
engine made and then forgot. A page that ends with nine hundred pixels free
ended for a reason — a hard break, a section, a column levelling that chose a
height — and that reason is the fix. Without it every pagination defect starts
with an hour of reconstructing what the engine was thinking.
Recorded only when asked for, so a reader pays nothing.
page
number
Zero-based page index.
columnCount
number
Columns the section asked for.
contentHeight
number
Height of the text area, in pixels.
insetHeight
number
How much the running parts took off the page, in pixels.
A header taller than the margin it sits in pushes the body down, and the
text area is the page less both margins *less this*. When a page holds a
few pixels fewer than the section declares, this is the only place the
missing pixels are recorded — and six of them, on a report full of tables,
was six pages.
balancedHeight
number | undefined
The height the columns were levelled to, where they were.
`undefined` on a page whose run carries on overleaf: there is nothing to
level until the run ends.
columnHeights
readonly number[]
Height used in each column.
columnBlocks
readonly number[]
Blocks placed in each column.
blocks
number
Blocks placed on the page.
stoppedAt
{ room: number; blockTop: number; blockBottom: number; floatBottom: number; divideFailure?: "keep-lines" | "no-split"; } | undefined
The block that did not fit, and the room the column had for it.
The fact a finished page no longer holds, and the one that says whether a
page ended honestly. A block whose top is already past the room had nowhere
to go; a block that starts well inside it and is merely tall is a
measurement to look at.
continued
boolean
Whether this page continues a run that began on the page before it.
endedBy
"full" | "hard-break" | "section" | "levelled"
What ended the page.
`full` — the next block did not fit. `hard-break` — a page or column break
in the content. `section` — the section ran out of blocks. `levelled` — the
columns were levelled to less than the text area, which ends the page as
surely as filling it does and is the decision most often wrong.
LineBreakStats
interface LineBreakStats
How many paragraphs each path took.
Named to match `LayoutProfile`, which is what a run actually passes in: the
question "how much of this document did the new path handle" belongs beside
the timings, not in a second place a reader has to find.
paragraphsOwn
number
Paragraphs broken here.
paragraphsBrowser
number
Paragraphs left to the browser, because something about them is unsupported.
linesOwn
number
Lines produced here.
skippedByReason
Record<string, number>
Why the paragraphs that fell back did.
A count alone cannot be read: "eighty thousand paragraphs went to the
browser" is a different fact if they are all table cells from what it is if
they are all floats, and the two point at entirely different work.
PageLayout
interface PageLayout
One laid-out page.
index
number
Zero-based page index across the whole document.
section
SectionProperties
Page setup this page was laid out with.
items
HTMLElement[]
Content of the page, in order.
The elements are detached from the document until the page is attached by
the virtualiser, which is what keeps a thousand-page document from holding
a thousand pages of DOM.
flows
PageFlow[]
The same content, grouped by the section each run was laid out under.
usedHeight
number
Used height of the text area in pixels.
displayNumber
number
Page number as displayed, honouring section restarts.
numberFormat
string | undefined
Number format for the displayed page number, from `w:pgNumType`.
sectionIndex
number
Index of the section this page belongs to.
firstOfSection
boolean
True when this is the first page of its section.
footnoteIds
string[]
Footnote ids referenced from this page, in order of appearance.
PendingField
interface PendingField
A field whose value depends on the final pagination.
fieldType
string
`PAGE`, `NUMPAGES`, `PAGEREF` or `SECTIONPAGES`.
target
string | undefined
Bookmark name for `PAGEREF`.
format
string | undefined
Number format from the field switches, e.g. `\* ROMAN`.
RenderContext
interface RenderContext
Everything the renderer needs while producing DOM for one document.
options
Required<Pick<DocxRenderOptions, "renderHeaders" | "renderFooters" | "renderFootnotes" | "renderEndnotes" | "renderComments" | "renderTrackedChanges" | "paginate" | "classPrefix" | "zoom" | "lineBreaking">>
metrics
TextMetricsCache
Advances of the document's fonts, read from the fonts themselves.
Shared for the life of a view: a document repeats the same words in the same
formatting constantly, so the cache behind this answers most measurements
without touching the font at all.
numbering
NumberingCounter
Advances list numbering; shared so numbers stay correct across pages.
footnotes
ReadonlyMap<string, Note>
Footnotes and endnotes, loaded before rendering starts.
endnotes
ReadonlyMap<string, Note>
comments
ReadonlyMap<string, Comment>
ownerPart
string | undefined
The package part the content being rendered came from.
Relationship ids are scoped to their owning part, so a `r:id` inside a
header resolves against the header's own `.rels` file, not the document's.
Getting this wrong makes images in headers silently disappear.
tasks
Promise<void>[]
Deferred work: image loading and anything else that must not block layout.
pendingFields
PendingField[]
Field placeholders that need a page number substituted after pagination.
Page numbers cannot be known while the content is being laid out, so the
renderer emits a marked element and the layout engine fills it in once the
page it landed on is known.