Home  ›  Guides  ›  Form filling

Form filling & flattening

New in v1.6.0. Read, fill, and flatten the interactive AcroForm fields of existing PDFs — whether authored by pdfnative or a third party — via non-destructive incremental update. Complements the form builder (which creates fields from scratch).

TL;DR#

import { readFormFields, fillForm, flattenForm } from 'pdfnative';
import { readFileSync, writeFileSync } from 'node:fs';

const src = readFileSync('application.pdf');

// 1. Discover the fields
for (const f of readFormFields(src)) {
  console.log(f.name, f.type, f.value);
}

// 2. Fill by field name
const filled = fillForm(src, {
  fullName: 'Ada Lovelace',
  agree: true,               // checkbox
  country: 'France',         // dropdown option
});
writeFileSync('filled.pdf', filled);

// 3. Optionally flatten (make it non-editable)
writeFileSync('flat.pdf', flattenForm(filled));

readFormFields(bytes, options?)#

Returns a ParsedFormField[] describing every terminal field:

interface ParsedFormField {
  name: string;                               // fully-qualified (dotted) name
  type: 'text' | 'checkbox' | 'radio' | 'dropdown' | 'listbox'
      | 'button' | 'signature' | 'unknown';
  value: string | string[] | boolean | null;
  readOnly: boolean;
  required: boolean;
  multiline: boolean;
  options?: { export: string; label: string }[]; // choice fields
  maxLen?: number;
  onState?: string;                           // checkbox/radio "on" state name
  widgets: { pageIndex: number; rect: [number, number, number, number] }[];
  ref: number;                                // terminal field object number
}

Inherited attributes (/FT, /Ff, /DA, /Opt, /MaxLen) are resolved up the /Parent chain, and UTF-16BE names/values are decoded.

fillForm(bytes, values, options?)#

values maps fully-qualified field name → value:

Field type Value
text / multiline string
dropdown string (one option's export/label)
listbox string or string[] (multi-select)
checkbox / radio boolean, or the export-state string
interface FillFormOptions {
  flatten?: boolean;                          // fill then flatten in one call
  onUnknownField?: 'throw' | 'ignore';        // default 'throw'
  nonWinAnsi?: 'throw' | 'needAppearances';   // default 'throw'
  password?: string;                          // for encrypted documents (see below)
}

Errors: FormFieldNotFoundError, FormValueTypeError, FormUnsupportedError.

flattenForm(bytes, options?)#

Stamps each widget's appearance into its page content and removes the interactive layer (/AcroForm, widget /Annots):

interface FlattenFormOptions {
  force?: boolean;      // flatten even over a signed signature field
  password?: string;    // for encrypted documents
}

Flattening a document with a signed signature field throws by default (flattening is destructive to what was signed); pass { force: true } to override.

Encrypted & signed documents#

How it works#

Both operations use the incremental modifier (createModifier), so the original bytes are never rewritten — the update is appended after the existing body with a new xref and a /Prev chain. That is why signatures on earlier revisions stay valid.

Searchable form text (v1.7.0). The AcroForm /Helv font dictionary now carries a /ToUnicode CMap in every mode, so text typed into form fields is searchable and extractable (see the text extraction guide). Because of that CMap, every form-carrying document changes bytes compared to v1.6.0 output (about 20 bytes) — a deliberate correctness fix, recorded in the v1.7.0 release notes. Under a PDF/A claim, a form field also raises the PDFA_UNEMBEDDED_FORM_FONT diagnostic (see the PDF/A guide).

See also#