Skip to content

Forms

An interactive PDF form, an AcroForm, is a document-level collection of fields that a viewer lets the user edit: text boxes, checkboxes, radio groups, dropdown and list boxes, push buttons and signature fields. UniPDF reads that collection through reader.AcroForm, a *model.PdfAcroForm, and creates one with model.NewPdfAcroForm().

The field tree

PdfAcroForm.Fields holds only the top-level fields. Fields nest through PdfField.Kids, so a form is a tree, and form.AllFields() is the flattened list you almost always want to iterate. It returns nil on a nil form, which matters because a document with no form has reader.AcroForm == nil.

Two things are separate in a field, and confusing them is the usual source of “my value is in the file but nothing shows up”:

PartWhat it is
The fieldThe data. Name (T), value (V), default value (DV), flags (Ff).
The widget annotationThe appearance. A PdfAnnotationWidget in field.Annotations, positioned by its Rect and attached to a page.

A field can own several widgets, which is how one value appears in more than one place, and how a radio group’s buttons are siblings under a single parent field. Viewers do not draw V; they draw the widget’s appearance stream. That is why setting a value is not always enough on its own, and why appearance generation gets its own guides below.

Names come in two forms. PartialName() is the field’s own T string; FullName() is the dotted path from the root, parent.child. A field inside a parent has both, and they are not the same string.

The specific field type lives in the context object rather than in PdfField:

switch t := field.GetContext().(type) {
case *model.PdfFieldText:
    // text box; t.MaxLen, t.Q for alignment
case *model.PdfFieldButton:
    // t.IsCheckbox(), t.IsRadio(), t.IsPush()
case *model.PdfFieldChoice:
    // t.Opt holds the available options
case *model.PdfFieldSignature:
    // signature placeholder
}

Filling versus flattening

These are different operations with different outcomes, and a lot of workflows do both in sequence.

FillFlatten
Callform.Fill / form.FillWithAppearancereader.FlattenFields / FlattenFieldsWithOpts
Field valuesSet in the AcroFormDrawn into the page content stream
Still editableYesNo
Fields afterwardsPresentRemoved from the page’s Annots and from the AcroForm
Text extractable as contentNo, it lives in the field valueYes

Filling keeps the document interactive. The value is stored in the field, so a viewer can change it again, form data can be exported, and a later pass can read the value back out. What you lose is control over presentation: what the reader actually sees is whatever appearance stream is attached to the widget, and different viewers disagree about how much they are willing to regenerate on their own.

Flattening bakes the current appearance into the page and deletes the fields. Everything renders identically everywhere, the text becomes extractable page content, and nobody can edit it. What you lose is everything about the form: no more values to read back, no export, and no way to undo it in the same document. Flatten a copy, not your only copy.

The trap in between is a field that has a value but no appearance stream. Fill does not generate appearances; flattening such a field draws nothing at all and you get a blank space where the value should be. Pass an annotator.FieldAppearance to FillWithAppearance or to FlattenFields to have UniPDF generate the appearance itself.

Where to look

GuideCovers
List form fieldsWalking the field tree, reading names, types and values.
Fill form fieldsSetting values from JSON, keeping the form editable.
Create formBuilding fields and widget annotations from scratch.
Flatten formBaking appearances into the page and dropping the fields.
Fill and flatten with appearanceGenerating appearance streams so flattened values are visible.
Custom text colorPer-field colors and fonts through AppearanceStyle.

For signature fields specifically, see the signature guides. Signature fields are AcroForm fields, but signing has its own flow and flattening a signed document invalidates the signature.

Last updated on