docxRenderer

Last updated on

Render Paradoc artifacts to Word documents

Render forms to DOCX (Word) documents with Paradoc's dependency-light Open XML implementation. It supports placeholders, conditionals, loops, custom delimiters, split Word runs, and automatic field formatting. Every condition, loop source, and placeholder is an artifact expression, so a condition means the same thing in a Word layer as in a field rule.

Example

import { p } from '@paradoc/core'
import { docxRenderer } from '@paradoc/render/docx'
import { createFsResolver } from '@paradoc/resolvers/fs'
import { writeFileSync } from 'node:fs'

const resolver = createFsResolver({ root: process.cwd() })

const form = p.form({
  name: 'contract',
  fields: {
    clientName: { type: 'text', label: 'Client Name' },
    contractValue: { type: 'money', label: 'Contract Value' },
    startDate: { type: 'date', label: 'Start Date' }
  },
  layers: {
    docx: {
      kind: 'file',
      mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      path: '/templates/contract-template.docx'
    }
  },
  defaultLayer: 'docx'
}, { resolver })

// Fill the form with data
const filled = form.fill({
  fields: {
    clientName: 'Acme Corp',
    contractValue: { amount: 50000, currency: 'USD' },
    startDate: '2024-04-01'
  }
})

// The resolver was bound when the form was constructed, so every instance
// derived from it — filled included — carries it. render() doesn't take one.
const output = await filled.render({
  renderer: docxRenderer()
})

// output is Uint8Array - write to file
writeFileSync('contract-filled.docx', output)

Import

From the unified package's DOCX entry point:

import { docxRenderer } from '@paradoc/render/docx'

API

docxRenderer()

Factory function that creates a configured DOCX renderer instance.

function docxRenderer(options?: DocxRendererOptions): ParadocRenderer<
  RendererLayer & { type: 'docx'; content: Uint8Array },
  Uint8Array
>

Parameters

options?: DocxRendererOptions
Configuration options

DocxRendererOptions

formatter?: Formatter
Artifact value formatter. Defaults to en-US.
signatureOptions?: DocxSignatureOptions
Options for signature and initials template marker rendering.
expressions?: { functions?, signatures? }
Host functions templates can call, with their signatures.

DocxSignatureOptions

placeholder?: { signature?, initials?, signatureDate?, capacity?, printedName? }
Placeholder text/function for unsigned signing marks.
captured?: { signature?, initials?, signatureDate?, capacity?, printedName? }
Text/function for captured signing marks.

Returns

Returns an ParadocRenderer object with:

id: "docx"
Renderer identifier
Methods
render: (request: RenderRequest) => Promise<Uint8Array>
Async render function that returns the filled document

renderDocx()

Low-level function for direct DOCX rendering without the full renderer interface.

async function renderDocx(options: RenderDocxOptions): Promise<Uint8Array>

RenderDocxOptions

template: Uint8Array
DOCX template file as binary data
data: Record<string, unknown>
Data object to populate the template
form?: Form
Form schema for automatic field type detection and formatting
formatter?: Formatter
Artifact value formatter. Defaults to en-US.
signatureOptions?: DocxSignatureOptions
Options for signature and initials rendering
options?: DocxRenderOptions
DOCX-specific rendering options
expressions?: TemplateExpressionOptions
The expression context (`context`), or configured `functions` and their `signatures`. Artifact renders supply the artifact context.
layer?: string
Layer key, named in template errors

DocxRenderOptions

cmdDelimiter?: [string, string]
Custom command delimiter. Defaults to ["{{", "}}"]
processLineBreaks?: boolean
Convert newlines to line breaks. Defaults to true.

Returns

Returns a Promise<Uint8Array> containing the rendered DOCX document.

Template Syntax

DOCX templates use control paragraphs for blocks and {{ }} placeholders inside text. Every expression is an artifact expression:

Contract for {{fields.clientName}}

Total Value: {{fields.contractValue}}
Start Date: {{fields.startDate}}

{{IF fields.discountPercent > 0}}
Discount Applied: {{fields.discountPercent}}
{{ELSE}}
No discount.
{{END-IF}}

{{FOR line IN fields.lines}}
{{index(line) + 1}}. {{line.description}}: {{line.amount}}
{{END-FOR line}}

A FOR loop names its row (line above), and index(line), first(line), and last(line) give its position. A FOR paragraph inside a table row repeats the row. Text paragraphs can also use the text-template markers ({{#if}}, {{#each}}), where the row is item.

Supported Features

SyntaxDescription
{{fields.fieldName}}Insert a value, formatted for its type
{{fields.qty * fields.price}}Insert any expression
{{IF condition}}...{{ELSE}}...{{END-IF}}Conditional paragraphs; the condition must be boolean
{{FOR row IN list}}...{{END-FOR row}}Repeat paragraphs or table rows
{{signature(parties.client, "client-sign")}}Place a signing mark; initials, signatureDate, capacity, and printedName work the same way

The signing directives print as in text templates, with underlines in place of the bracketed placeholders:

DirectiveBefore captureAfter capture
signature_____________________________[Signed]
initials______[Initialed]
signatureDate__________the capture's YYYY-MM-DD date
capacitythe signatory's capacity, else ________________the captured text, else the signatory's capacity, else underscores
printedNamethe signer's person.name, else _______________________the captured text, else the signer's person.name, else underscores

signatureOptions.placeholder and signatureOptions.captured replace this text, as they do for text layers. For capacity and printedName, a known capacity or name wins over placeholder.

The old comparison syntax (===, !==, and $row loop names) is no longer accepted: write == and !=, and name the row directly ({{line.amount}}).

checkDocxTemplate()

Checks every control command and expression in a Word package against a type environment. validateLayers() runs it on file-backed DOCX layers. Each diagnostic names the part and paragraph, such as word/document.xml paragraph 12.

Automatic Formatting

When a form schema is provided, field values are automatically formatted:

// Money fields formatted as "$50,000.00"
// Date fields formatted as "Apr 1, 2024"
// Phone fields formatted as "(555) 123-4567"

Custom Formatters

Use a formatter for different locales:

import { renderDocx } from '@paradoc/render/docx'
import { createFormatter } from '@paradoc/format'

const output = await renderDocx({
  template: templateBytes,
  data,
  form,
  formatter: createFormatter({ locale: 'de-DE' }),
})
// EUR amounts use German number formatting; currency stays explicit in the value.

Formatting failures reject the render with the field path and status. Invalid values and template errors never produce a silently unfinished document. An artifact-level formatter passed to render() overrides the renderer default.

Values in templates

A DOCX template names each value by its path, such as {{fields.clientFullName}}. A DOCX layer takes no bindings or bindingsFrom, and validation rejects them there: bindings belong to PDF layers, where they map AcroForm field names to Paradoc paths.

On this page