# docxRenderer

Render Paradoc artifacts to Word documents

Canonical URL: https://docs.paradoc.dev/sdk/renderers/docx/

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](/concepts/logic), so a
condition means the same thing in a Word layer as in a field rule.

## Example

```ts
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:

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

## API

### docxRenderer()

Factory function that creates a configured DOCX renderer instance.

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

#### Parameters

| Name | Type | Description |
| --- | --- | --- |
| `options?` | `DocxRendererOptions` | Configuration options |

#### DocxRendererOptions

| Name | Type | Description |
| --- | --- | --- |
| `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

| Name | Type | Description |
| --- | --- | --- |
| `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:

| Name | Type | Description |
| --- | --- | --- |
| `id` | `"docx"` | Renderer identifier |

**Methods**

| Name | Type | Description |
| --- | --- | --- |
| `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.

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

#### RenderDocxOptions

| Name | Type | Description |
| --- | --- | --- |
| `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

| Name | Type | Description |
| --- | --- | --- |
| `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

| Syntax                                         | Description                                                                                        |
| ---------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `{{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](/sdk/renderers/text#signature-and-initials-directives), with underlines in place of the bracketed placeholders:

| Directive       | Before capture                                             | After capture                                                        |
| --------------- | ---------------------------------------------------------- | -------------------------------------------------------------------- |
| `signature`     | `_____________________________`                            | `[Signed]`                                                           |
| `initials`      | `______`                                                   | `[Initialed]`                                                        |
| `signatureDate` | `__________`                                               | the capture's `YYYY-MM-DD` date                                      |
| `capacity`      | the signatory's `capacity`, else `________________`        | the captured text, else the signatory's `capacity`, else underscores |
| `printedName`   | the 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:

```ts
// 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:

```ts
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](/sdk/renderers/pdf), where they map AcroForm field names to Paradoc paths.

## Related

* [Renderers](/sdk/renderers) - Renderer interface overview
* [Formatting](/sdk/formatting) - Value formatting
