LibPDF

PDFForm

Form class for reading, filling, creating, and flattening interactive form fields.

PDFForm

The PDFForm class manages interactive forms (AcroForms) in a PDF document. It provides methods for reading, filling, creating, and flattening form fields.

const pdf = await PDF.load(bytes);
const form = await pdf.getForm();

if (form) {
  await form.fill({
    name: "John Doe",
    email: "john@example.com",
    agree: true,
  });
}

Properties

fieldCount

Number of fields in the form.

Type: number (readonly)


isEmpty

Whether the form has no fields.

Type: boolean (readonly)


hasUnsavedChanges

Whether any field has been modified and needs appearance update.

Type: boolean (readonly)


properties

Form-level properties.

Type: FormProperties (readonly)

interface FormProperties {
  defaultAppearance: string;
  defaultAlignment: TextAlignment;
  needAppearances: boolean;
  hasSignatures: boolean;
  isAppendOnly: boolean;
}

Field Access

getFields()

Get all form fields.

Returns: FormField[]

const fields = form.getFields();
for (const field of fields) {
  console.log(`${field.name}: ${field.type}`);
}

getFieldNames()

Get the names of all fields.

Returns: string[]

const names = form.getFieldNames();
// ["name", "email", "phone", "agree"]

getField(name)

Get a field by name (untyped).

ParamTypeDescription
namestringField name

Returns: FormField | undefined

const field = form.getField("name");
if (field?.type === "text") {
  console.log(field.getValue());
}

hasField(name)

Check if a field exists.

ParamTypeDescription
namestringField name

Returns: boolean


Type-Safe Field Access

These methods return properly typed fields, or undefined if not found or wrong type.

getTextField(name)

Get a text field by name.

Returns: TextField | undefined

const nameField = form.getTextField("name");
if (nameField) {
  await nameField.setValue("John Doe");
  console.log(nameField.getValue());
}

getCheckbox(name)

Get a checkbox field by name.

Returns: CheckboxField | undefined

const agree = form.getCheckbox("terms");
if (agree) {
  await agree.check();
  console.log(agree.isChecked()); // true
}

getRadioGroup(name)

Get a radio button group by name.

Returns: RadioField | undefined

const payment = form.getRadioGroup("payment_method");
if (payment) {
  await payment.setValue("credit_card");
  console.log(payment.getOptions()); // ["credit_card", "paypal", "bank"]
}

getDropdown(name)

Get a dropdown (combo box) field by name.

Returns: DropdownField | undefined

const country = form.getDropdown("country");
if (country) {
  await country.setValue("United States");
  const options = country.getOptions();
  // options: [{ value: "USA", display: "United States" }, ...]
}

getListBox(name)

Get a list box field by name.

Returns: ListBoxField | undefined

const colors = form.getListBox("favorite_colors");
if (colors) {
  await colors.setValue(["red", "blue"]);
}

getSignatureField(name)

Get a signature field by name.

Returns: SignatureField | undefined

const sig = form.getSignatureField("signature1");
if (sig) {
  console.log(sig.isSigned());
}

getButton(name)

Get a button field by name.

Returns: ButtonField | undefined


Bulk Field Access

getTextFields()

Get all text fields.

Returns: TextField[]


getCheckboxes()

Get all checkboxes.

Returns: CheckboxField[]


getRadioGroups()

Get all radio button groups.

Returns: RadioField[]


getDropdowns()

Get all dropdowns.

Returns: DropdownField[]


getListBoxes()

Get all list boxes.

Returns: ListBoxField[]


getSignatureFields()

Get all signature fields.

Returns: SignatureField[]


getButtons()

Get all buttons.

Returns: ButtonField[]


Bulk Operations

fill(values)

Fill multiple fields at once.

ParamTypeDescription
valuesRecord<string, FieldValue>Field names to values

Returns: Promise<{ filled: string[], skipped: string[] }>

Throws: TypeError - If a value type doesn't match the field type

This method is lenient: fields that don't exist are silently skipped.

const result = await form.fill({
  name: "John Doe",
  email: "john@example.com",
  agree: true,           // checkbox
  country: "USA",        // dropdown
  colors: ["red", "blue"], // listbox
  nonexistent: "ignored",
});

console.log(result.filled);  // ["name", "email", "agree", "country", "colors"]
console.log(result.skipped); // ["nonexistent"]

FieldValue Types:

Field TypeValue Type
Textstring
Checkboxboolean or string
Radiostring or null
Dropdownstring
Listboxstring[]

resetAll()

Reset all fields to their default values.

await form.resetAll();

Field Creation

createTextField(name, options?)

Create a new text field.

ParamTypeDefaultDescription
namestringrequiredUnique field name
[options]TextFieldOptions
[options.font]EmbeddedFontFont for text
[options.fontSize]number0 (auto)Font size
[options.color]ColorblackText color
[options.maxLength]numberMax characters
[options.multiline]booleanfalseMultiline input
[options.password]booleanfalseMask input
[options.comb]booleanfalseFixed-width cells
[options.alignment]TextAlignmentLeftText alignment
[options.defaultValue]stringDefault value
[options.backgroundColor]ColorBackground
[options.borderColor]ColorBorder
[options.borderWidth]number1Border width

Returns: TextField

Throws: Error - If field name already exists

const nameField = form.createTextField("name", {
  fontSize: 12,
  maxLength: 100,
  defaultValue: "John Doe",
});

// Place on page
await page.drawField(nameField, {
  x: 100,
  y: 700,
  width: 200,
  height: 24,
});

createCheckbox(name, options?)

Create a new checkbox field.

ParamTypeDefaultDescription
namestringrequiredUnique field name
[options]CheckboxOptions
[options.onValue]string"Yes"Value when checked
[options.symbol]CheckboxSymbol"check"Symbol style
[options.defaultChecked]booleanfalseInitially checked
[options.backgroundColor]ColorBackground
[options.borderColor]ColorBorder
[options.borderWidth]number1Border width

Returns: CheckboxField

CheckboxSymbol: "check" | "cross" | "square"

const agree = form.createCheckbox("agree", {
  onValue: "Yes",
  symbol: "check",
  defaultChecked: true,
});

await page.drawField(agree, {
  x: 100,
  y: 650,
  width: 18,
  height: 18,
});

createRadioGroup(name, options)

Create a new radio button group.

ParamTypeDefaultDescription
namestringrequiredUnique field name
optionsRadioGroupOptionsrequired
options.optionsstring[]requiredAvailable values
[options.symbol]RadioSymbol"circle"Symbol style
[options.defaultValue]stringInitially selected
[options.backgroundColor]ColorBackground
[options.borderColor]ColorBorder
[options.borderWidth]number1Border width

Returns: RadioField

Throws:

  • Error - If field name already exists
  • Error - If options array is empty

RadioSymbol: "circle" | "check"

const payment = form.createRadioGroup("payment", {
  options: ["Credit Card", "PayPal", "Bank Transfer"],
  defaultValue: "Credit Card",
});

// Each option needs its own widget
await page.drawField(payment, {
  x: 100,
  y: 550,
  width: 16,
  height: 16,
  option: "Credit Card",
});
await page.drawField(payment, {
  x: 100,
  y: 520,
  width: 16,
  height: 16,
  option: "PayPal",
});
await page.drawField(payment, {
  x: 100,
  y: 490,
  width: 16,
  height: 16,
  option: "Bank Transfer",
});

createDropdown(name, options)

Create a new dropdown (combo box) field.

ParamTypeDefaultDescription
namestringrequiredUnique field name
optionsDropdownOptionsrequired
options.optionsstring[]requiredAvailable values
[options.font]EmbeddedFontFont for text
[options.fontSize]numberFont size
[options.color]ColorText color
[options.editable]booleanfalseAllow custom input
[options.defaultValue]stringInitially selected
[options.backgroundColor]ColorBackground
[options.borderColor]ColorBorder

Returns: DropdownField

Throws: Error - If options array is empty

const country = form.createDropdown("country", {
  options: ["USA", "Canada", "UK", "Germany"],
  defaultValue: "USA",
  fontSize: 11,
});

await page.drawField(country, {
  x: 100,
  y: 600,
  width: 200,
  height: 24,
});

createListbox(name, options)

Create a new list box field.

ParamTypeDefaultDescription
namestringrequiredUnique field name
optionsListboxOptionsrequired
options.optionsstring[]requiredAvailable values
[options.font]EmbeddedFontFont for text
[options.fontSize]numberFont size
[options.color]ColorText color
[options.multiSelect]booleanfalseAllow multiple selection
[options.defaultValue]string[]Initially selected
[options.backgroundColor]ColorBackground
[options.borderColor]ColorBorder

Returns: ListBoxField

Throws: Error - If options array is empty

const colors = form.createListbox("colors", {
  options: ["Red", "Green", "Blue", "Yellow"],
  multiSelect: true,
  defaultValue: ["Red", "Blue"],
});

await page.drawField(colors, {
  x: 100,
  y: 400,
  width: 150,
  height: 100,
});

createSignatureField(name, options?)

Create a new signature field.

ParamTypeDefaultDescription
namestringrequiredUnique field name
[options]SignatureFieldOptions
[options.backgroundColor]ColorBackground
[options.borderColor]ColorBorder
[options.borderWidth]number1Border width

Returns: SignatureField

const sigField = form.createSignatureField("Signature1");
// Sign later via pdf.sign({ fieldName: "Signature1", ... })

Form Operations

updateAppearances()

Regenerate appearance streams for all modified fields.

await form.updateAppearances();

flatten(options?)

Flatten all form fields into static page content.

ParamTypeDefaultDescription
[options]FlattenOptions

After flattening:

  • Field appearances become static page content
  • Widget annotations are removed
  • The form can no longer be edited
await form.fill({ name: "John", email: "john@example.com" });
await form.flatten();
const bytes = await pdf.save();

reloadFields()

Reload fields from the underlying AcroForm.

Call this if the form structure has been modified externally.

await form.reloadFields();

acroForm()

Get the underlying AcroForm for low-level operations.

Returns: AcroForm

const acroForm = form.acroForm();
console.log(acroForm.defaultAppearance);

Field Types

TextField

Method/PropertyReturnsDescription
getValue()stringGet current value
setValue(value)Promise<void>Set value
maxLengthnumberMax length (0 = no limit)
isMultilinebooleanWhether multiline
setFont(font)voidSet font
setFontSize(size)voidSet font size
setTextColor(r, g, b)voidSet text color

CheckboxField

MethodReturnsDescription
isChecked()booleanCheck state
check()Promise<void>Check the box
uncheck()Promise<void>Uncheck the box
setValue(value)Promise<void>Set by value string
getOnValue()stringGet the "on" value

RadioField

MethodReturnsDescription
getValue()string | nullGet selected option
setValue(value)Promise<void>Select option
getOptions()string[]Get available options

Method/PropertyReturnsDescription
getValue()stringGet selected value
setValue(value)Promise<void>Select value
getOptions()ChoiceOption[]Get available options
isEditablebooleanWhether editable
setFont(font)voidSet font
setFontSize(size)voidSet font size

ListBoxField

Method/PropertyReturnsDescription
getValue()string[]Get selected values
setValue(values)Promise<void>Set selected values
getOptions()ChoiceOption[]Get available options
isMultiSelectbooleanWhether multi-select
setFont(font)voidSet font
setFontSize(size)voidSet font size

SignatureField

MethodReturnsDescription
isSigned()booleanCheck if signed

Types

TextAlignment

const TextAlignment = {
  Left: 0,
  Center: 1,
  Right: 2,
} as const;

type TextAlignment = 0 | 1 | 2;

FieldValue

type FieldValue = string | boolean | string[] | null;

ChoiceOption

interface ChoiceOption {
  value: string;   // Export value
  display: string; // Display text (may equal value)
}

FormField

interface FormField {
  name: string;
  type: FieldType;
  isReadOnly(): boolean;
  isRequired(): boolean;
}

type FieldType = 
  | "text"
  | "checkbox"
  | "radio"
  | "dropdown"
  | "listbox"
  | "signature"
  | "button";

On this page