OpenForm

pdfRenderer

Last updated on

Fill PDF forms with AcroForm field support

Fill PDF forms by populating AcroForm fields with form data. Built on pdf-lib, supporting text fields, checkboxes, dropdowns, and radio buttons with automatic field serialization.

Example

import { open } from '@open-form/core'
import { pdfRenderer } from '@open-form/renderer-pdf'

const form = open.form({
  name: 'w9',
  fields: {
    name: { type: 'text', label: 'Name' },
    businessName: { type: 'text', label: 'Business Name' },
    taxClassification: { type: 'enum', enum: ['individual', 'llc', 'corporation'] },
    address: { type: 'text', label: 'Address' },
    ssn: { type: 'text', label: 'SSN' }
  },
  layers: {
    pdf: {
      kind: 'file',
      mimeType: 'application/pdf',
      path: '/templates/w9-form.pdf',
      bindings: {
        // Map PDF field names to form field expressions
        'topmostSubform[0].Page1[0].f1_1[0]': 'name',
        'topmostSubform[0].Page1[0].f1_2[0]': 'businessName',
        'topmostSubform[0].Page1[0].c1_1[0]': 'taxClassification:individual',
        'topmostSubform[0].Page1[0].c1_1[1]': 'taxClassification:llc',
        'topmostSubform[0].Page1[0].f1_5[0]': 'address'
      }
    }
  },
  defaultLayer: 'pdf'
})

// Fill the form with data
const filled = form.fill({
  fields: {
    name: 'John Smith',
    businessName: 'Smith Consulting',
    taxClassification: 'llc',
    address: '123 Main St, New York, NY 10001'
  }
})

// Render the filled form
const output = await filled.render({
  renderer: pdfRenderer()
})

// output is Uint8Array - write to file
fs.writeFileSync('w9-filled.pdf', output)

Import

From the umbrella package:

import { pdfRenderer } from '@open-form/renderers'

Or from the individual package:

import { pdfRenderer } from '@open-form/renderer-pdf'

API

pdfRenderer()

Factory function that creates a configured PDF renderer instance.

function pdfRenderer(options?: PdfRendererOptions): OpenFormRenderer<
  RendererLayer & { type: 'pdf'; content: Uint8Array },
  Uint8Array
>

Parameters

options?: PdfRendererOptions
Configuration options

PdfRendererOptions

serializers?: SerializerRegistry
Custom serializer registry for formatting field values. Defaults to USA serializers.
signatureOptions?: PdfSignatureOptions
Options for signature and initials rendering (future feature).

PdfSignatureOptions

placeholder?: { signature?: string | Function, initials?: string | Function }
Placeholder text/function for unsigned signatures and initials.
captured?: { signature?: string | Function, initials?: string | Function }
Text/function for captured signatures and initials.

Returns

Returns an OpenFormRenderer object with:

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

renderPdf()

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

async function renderPdf(options: RenderPdfOptions): Promise<Uint8Array>

RenderPdfOptions

template: Uint8Array
PDF template file as binary data
form: Form
Form schema for field type detection
data: Record<string, unknown>
Data object to populate form fields
bindings?: Record<string, string>
Mapping from PDF field names to form field expressions
serializers?: SerializerRegistry
Custom serializer registry. Defaults to USA serializers.
signatureOptions?: PdfSignatureOptions
Options for signature and initials rendering

Returns

Returns a Promise<Uint8Array> containing the filled PDF document.

inspectAcroFormFields()

Utility function to inspect AcroForm fields in a PDF template.

async function inspectAcroFormFields(
  template: Uint8Array,
  options?: InspectOptions
): Promise<PdfFieldInfo[]>

Parameters

template: Uint8Array
PDF template file as binary data
options?: InspectOptions
Inspection options

InspectOptions

includeButton?: boolean
Include button fields in results. Defaults to false.
includeSignature?: boolean
Include signature fields in results. Defaults to false.

PdfFieldInfo

name: string
AcroForm field name
type: "text" | "checkbox" | "dropdown" | "radio" | "button" | "signature" | "unknown"
Field type
value?: string | boolean | string[]
Current field value
required?: boolean
Whether field is marked required

Inspecting PDF Fields

Use inspectAcroFormFields() to discover field names in a PDF template:

import { inspectAcroFormFields } from '@open-form/renderer-pdf'
import fs from 'fs'

const template = fs.readFileSync('form.pdf')
const fields = await inspectAcroFormFields(template)

console.log(fields)
// [
//   { name: 'f1_1', type: 'text', required: true },
//   { name: 'c1_1', type: 'checkbox', value: false },
//   { name: 'dropdown1', type: 'dropdown', value: ['Option A'] }
// ]

Binding Syntax

PDF bindings map AcroForm field names to form field names with special syntax for complex cases:

Simple Binding

bindings: {
  'pdfFieldName': 'formFieldName'
}

Enum Checkboxes

For PDF checkboxes that represent enum values, use :value syntax:

bindings: {
  'checkbox_individual': 'taxType:individual',  // Check if taxType === 'individual'
  'checkbox_llc': 'taxType:llc',                // Check if taxType === 'llc'
  'checkbox_corp': 'taxType:corporation'        // Check if taxType === 'corporation'
}

Split Fields

For fields split across multiple PDF inputs (like SSN), use :partNumber syntax:

bindings: {
  'ssn_part1': 'ssn:1',  // First part: "123" from "123-45-6789"
  'ssn_part2': 'ssn:2',  // Second part: "45"
  'ssn_part3': 'ssn:3'   // Third part: "6789"
}

Combined Fields

Combine multiple form fields into one PDF field:

bindings: {
  'cityStateZip': 'city,state,zipCode'  // "San Francisco, CA, 94105"
}

Nested Paths

Access nested data using dot notation:

bindings: {
  'buyer_name': 'parties.buyer.fullName'
}

Automatic Serialization

Field values are automatically serialized based on their schema types:

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

Related

On this page