Concept · Interactive documents
What are PDF forms (AcroForm)?
Create & fill PDFs in code
Last updated: 2026-06-29
An AcroForm is the interactive-form layer of the PDF specification. It adds fields a person can type into, tick, and select, and that your software can fill in seconds, no printing, no scanning, no retyping. This guide explains the field types, how appearance streams work, and how to author, fill, and flatten a form entirely in code.
The analogy: a paper form made smart
Think of a paper form: pre-printed labels, blank boxes to write in, tick boxes down the side. Anyone can fill it with a pen. But every time it lands in an office, someone has to read it and type the answers into a computer. That is slow, error-prone, and scales to zero.
A PDF form is that same form, made smart. The fields are real interactive objects your software can reach into and fill programmatically (from a database record, an API response, or a form submission) at any volume, instantly, without human transcription. When you are done, you flatten the form: bake the values into the page as static content so the recipient gets a clean, finished document, not a half-editable curiosity.
The four field types
The PDF AcroForm specification defines four kinds of interactive
fields. rust-pdf supports all four and generates a correct
/AP appearance stream for each at authoring time,
so fields render in every viewer without the
NeedAppearances flag.
Text field
Free-form text entry, single or multi-line. Used for names, addresses, descriptions, any open answer.
Checkbox
A binary on/off toggle. Checked state renders a tick or cross using the built-in ZapfDingbats font.
Radio group
Mutually exclusive options: selecting one deselects the rest. Defined as a group sharing a field name.
Dropdown
A choice field presenting a fixed list of options. Software sets the selected value by name, not by index.
Two jobs: author a blank form, then fill it
Working with PDF forms involves two distinct operations. They are often done at separate times: the blank template lives in version control; filling happens at runtime from live data.
2. Filling
Load the template and write values into its fields programmatically.
- Load the form bytes into an
EditableDoc - Call
fill_text_field,set_checkbox,set_choice, orset_radiowith the field name and value - Dotted field names navigate the hierarchy:
applicant.nametargets the right widget automatically - Optionally call
flatten_forms()to bake values into static content (see below) - Save or stream the completed PDF
Flattening: making it final
A filled form is still interactive; a recipient could change the values. Flattening removes the form layer and burns the current values into the page as ordinary, non-editable content. The result looks identical in every viewer, but no field can be altered.
Flatten before archiving, emailing a signed copy, attaching to a record system, or converting to PDF/A for long-term storage. Once flattened the document behaves like any static PDF.
Where PDF forms are used
Any workflow where structured data needs to reach a human-readable PDF document, whether the human fills it or the software does.
Customer onboarding
Pre-fill application forms with data from your CRM, send a PDF ready to sign, flatten on receipt.
Government & tax forms
Agencies publish AcroForm templates; software fills them from taxpayer records and returns completed PDFs.
Contracts & agreements
Generate a contract pre-populated with party names, dates, and terms; send for e-signature or wet sign.
Database-driven generation
Pull thousands of records and render a unique filled, flattened PDF for each: invoices, statements, certificates.
Applications & surveys
Publish a blank AcroForm for users to fill in a viewer; collect the data back as field values, not images.
Interactive kiosks & portals
Serve a form in a web viewer; flatten and archive once submitted, keeping a human-readable audit trail.
How to author and fill a PDF form with rust-pdf
Place fields when authoring, then fill and flatten an existing form.
The generated /AP means no NeedAppearances
flag is required.
# pip install rustpdf
import rustpdf
# 1) Author a blank form
with rustpdf.Document() as doc:
doc.add_page()
doc.text_field("applicant.name", 0, [72, 690, 320, 712])
doc.checkbox("agree", 0, [72, 650, 90, 668], checked=False)
doc.dropdown("plan", 0, [72, 610, 260, 630], ["Basic", "Pro", "Enterprise"])
doc.save("form.pdf")
# 2) Fill it, then flatten to a final read-only copy
with rustpdf.EditableDoc.load(open("form.pdf", "rb").read()) as ed:
ed.fill_text_field("applicant.name", "Ada Lovelace")
ed.set_checkbox("agree", True)
ed.set_choice("plan", "Pro")
ed.flatten_forms() # bake values; no longer editable
ed.save("form_filled.pdf")
// dotnet add package RustPdf
using RustPdf;
using (var doc = new Document()) {
doc.AddPage();
doc.TextField("applicant.name", 0, (72, 690, 320, 712));
doc.Checkbox("agree", 0, (72, 650, 90, 668), false);
doc.Dropdown("plan", 0, (72, 610, 260, 630), new[]{ "Basic", "Pro", "Enterprise" });
doc.Save("form.pdf");
}
using var ed = EditableDoc.Load(File.ReadAllBytes("form.pdf"));
ed.FillTextField("applicant.name", "Ada Lovelace");
ed.SetCheckbox("agree", true);
ed.SetChoice("plan", "Pro");
ed.FlattenForms();
ed.Save("form_filled.pdf");
// go get github.com/rustpdf/rustpdf-go@latest
doc, _ := rustpdf.New()
doc.AddPage()
doc.TextField("applicant.name", 0, [4]float64{72, 690, 320, 712}, "", 0)
doc.Checkbox("agree", 0, [4]float64{72, 650, 90, 668}, false)
doc.Dropdown("plan", 0, [4]float64{72, 610, 260, 630}, []string{"Basic", "Pro", "Enterprise"}, -1, 0)
doc.Save("form.pdf")
doc.Close()
ed, _ := rustpdf.Load(mustRead("form.pdf"))
defer ed.Close()
ed.FillTextField("applicant.name", "Ada Lovelace")
ed.SetCheckbox("agree", true)
ed.SetChoice("plan", "Pro")
ed.FlattenForms()
ed.Save("form_filled.pdf")
// npm install rustpdf
const { Document, EditableDoc } = require("rustpdf");
const fs = require("fs");
const doc = new Document();
doc.addPage();
doc.textField("applicant.name", 0, [72, 690, 320, 712]);
doc.checkbox("agree", 0, [72, 650, 90, 668], false);
doc.dropdown("plan", 0, [72, 610, 260, 630], ["Basic", "Pro", "Enterprise"]);
doc.save("form.pdf");
const ed = EditableDoc.load(fs.readFileSync("form.pdf"));
ed.fillTextField("applicant.name", "Ada Lovelace");
ed.setCheckbox("agree", true);
ed.setChoice("plan", "Pro");
ed.flattenForms();
ed.save("form_filled.pdf");
Form fields use the built-in Helvetica and ZapfDingbats fonts for
their /AP streams, so no font file is needed. For
eight-language coverage (Python, C#, Go, Node, PHP, Ruby,
Delphi, Swift) see the documentation.
PDF forms FAQ
What is a PDF form / AcroForm?
An AcroForm is the interactive-form layer of the PDF specification. It adds fields (text boxes, checkboxes, radio buttons, and dropdowns) that a person can fill in a PDF viewer, or that software can fill programmatically. Each field is a widget annotation attached to a page, with an appearance stream that controls how it is drawn. AcroForm is part of the PDF standard and is supported by every major viewer.
What field types are supported in PDF forms?
The PDF AcroForm specification defines text fields (single or multi-line free text), checkboxes (on/off toggle), radio groups (one option from a mutually exclusive set), and choice fields such as dropdowns and list boxes. rust-pdf supports all four types: text_field, checkbox, radio_group, and dropdown.
How do I fill a PDF form in code?
Load the existing PDF into an editable document, then call fill_text_field, set_checkbox, set_choice, or set_radio with the field name and the desired value. In Python: ed.fill_text_field("applicant.name", "Ada Lovelace"). Hierarchical dotted names like applicant.name address a nested field inside a parent group. After filling, call flatten_forms() to produce a final, non-editable PDF.
What does flattening a form do?
Flattening bakes the current field values into the page as static, non-editable content and removes the interactive form layer. The result looks identical to the filled form in any viewer, but the fields can no longer be changed. Flattening is the right step before archiving a completed form, emailing a final copy, or attaching a document to a record system. Call flatten_forms() / FlattenForms() after filling to produce the final read-only PDF.
Do I need the NeedAppearances flag?
No. The NeedAppearances flag tells viewers to regenerate field appearances because the document's /AP streams are absent or stale. rust-pdf generates a correct /AP appearance stream for every field at authoring time, using the built-in Helvetica and ZapfDingbats fonts, so viewers render fields correctly without that flag. Avoiding NeedAppearances means the form looks right in every viewer, including those that ignore the flag.
Generate and fill PDF forms in your language
One Rust core, eight bindings: Python, C#/.NET, Go, Node.js, PHP, Ruby, Delphi, Swift. Prototype for free; license the corporate features when you ship.