Build and pre-fill a PDF form
At a glance
Section titled “At a glance”An AcroForm is the interactive form inside a PDF. In this recipe, you build one
and pre-fill its fields with starting values. The Core HasFormFields trait is
a form-authoring API: you create each field and provide its value in the same
call. Use the default argument for text fields, selected for choice fields,
and checked for checkboxes. The PDF opens with the fields already filled in,
and they stay editable in a conforming reader. Anyone who opens the file can
still change them. This recipe follows examples/30-form-fields.php.
Scope boundary. Core creates and fills form fields as it builds the document. It does not read a form that already exists in a third-party PDF or merge a value map into it. Here, “fill” means author the form with values, not load and fill an external PDF. Round-tripping an external form is a Premium and server capability, not a Core public API.
Install
Section titled “Install”composer require nextpdf/core:^3Conceptual overview
Section titled “Conceptual overview”An AcroForm field stores its current value in the V entry of the field
dictionary (ISO 32000-2 §12.7). It can also store an optional default value in
DV, which the field returns to when a reset-form action runs. NextPDF sets
V from the value you pass to each field constructor. Text rendering uses a
default appearance string (DA).
The profile is structural because the document includes a trailer /ID array.
The post-pass normalizes that changing identifier before comparison.
API surface
Section titled “API surface”NextPDF\Core\Concerns\HasFormFields (mixed into Document):
textField(string $name, float $x, float $y, float $w, float $h, string $default = '', array $options = []): staticcheckBox(string $name, float $x, float $y, float $size, bool $checked = false): staticradioButton(string $name, float $x, float $y, float $size, string $value, string $group): staticcomboBox(string $name, float $x, float $y, float $w, float $h, array $items, string $selected = ''): staticlistBox(string $name, float $x, float $y, float $w, float $h, array $items, string $selected = ''): staticbutton(string $name, float $x, float $y, float $w, float $h, string $caption, string $action = ''): static
The default, checked, and selected arguments contain the pre-fill values.
Code sample — Quick start
Section titled “Code sample — Quick start”<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Pre-filled Form');$doc->addPage();
// Text field pre-filled with a value (sets the field dictionary /V entry).$doc->textField(name: 'full_name', x: 20, y: 30, w: 90, h: 8, default: 'Ada Lovelace');
// Choice field pre-selected.$doc->comboBox( name: 'country', x: 20, y: 45, w: 90, h: 8, items: ['United Kingdom', 'Taiwan', 'Japan'], selected: 'Taiwan',);
// Checkbox pre-checked.$doc->checkBox(name: 'newsletter', x: 20, y: 60, size: 5, checked: true);
$doc->save(__DIR__ . '/prefilled-form.pdf');echo "Wrote prefilled-form.pdf\n";Code sample — Production
Section titled “Code sample — Production”The full example below mirrors examples/30-form-fields.php, a registration
form with several sections. It writes to NEXTPDF_COOKBOOK_OUTPUT for the
harness.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Customer Registration — Pre-filled');$doc->addPage();
$doc->setFont('helvetica', 'B', 20);$doc->cell(0, 14, 'Customer Registration Form', newLine: true);$doc->ln(4);
$leftMargin = 15.0;$fieldX = 70.0;$fieldW = 120.0;$fieldH = 8.0;$rowSpacing = 12.0;
// --- Personal information, pre-filled ---$prefill = [ 'full_name' => 'Ada Lovelace', 'phone' => '+44 20 7946 0000', 'company' => 'Analytical Engines Ltd',];
$y = 40.0;$doc->setFont('helvetica', '', 10);foreach ($prefill as $name => $value) { $doc->setXY($leftMargin, $y); $doc->cell(50, $fieldH, ucwords(str_replace('_', ' ', $name)) . ':'); $doc->textField( name: $name, x: $fieldX, y: $y, w: $fieldW, h: $fieldH, default: $value, options: ['maxLen' => 80], ); $y += $rowSpacing;}
// --- Choice field, pre-selected ---$y += 6;$doc->setXY($leftMargin, $y);$doc->cell(50, $fieldH, 'Country:');$doc->comboBox( name: 'country', x: $fieldX, y: $y, w: $fieldW, h: $fieldH, items: ['United States', 'United Kingdom', 'Germany', 'Japan', 'Taiwan'], selected: 'United Kingdom',);
// --- Checkboxes, pre-set ---$y += $rowSpacing + 6;$doc->setXY($leftMargin, $y);$doc->cell(0, 7, 'Subscribe to newsletter');$doc->checkBox(name: 'newsletter', x: $leftMargin + 70, y: $y, size: 5, checked: true);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false ? $out : __DIR__ . '/registration-prefilled.pdf');
echo "Wrote pre-filled registration form\n";Expected output:
Wrote pre-filled registration formWhen you open the PDF, every field is already filled in and remains editable.
Edge cases & gotchas
Section titled “Edge cases & gotchas”- Field names must be unique. Two fields that share a name become one logical field with a shared value in conforming readers. That is useful for linked fields, and a surprise otherwise.
- Radio group semantics.
radioButton()ties each option to agroup. The selected option is the one whosevaluematches the group’s value. Only one option per group is on at a time. maxLenis a hint. AmaxLenoption caps input length in conforming readers. It does not limit the stored value you pre-fill.- Coordinates are top-left in the API. The trait converts to PDF’s bottom-left origin for you, so pass top-left coordinates, as the example shows.
- No external-PDF fill. No Core method loads an existing third-party form and applies a value map. See the scope boundary above.
Performance
Section titled “Performance”Form authoring scales linearly with the field count. Each field adds one widget annotation and one appearance. A few hundred fields stay well inside the 1500 ms / 64 MB budget.
Security notes
Section titled “Security notes”Pre-filled values are written verbatim into the field dictionary. Escape or validate any value from untrusted input before you place it in a document you distribute. A pre-filled form is not protected: anyone who can open the PDF can read and change the values. When the form content is sensitive, combine this recipe with Encrypt with permissions, and note the reader-cooperative caveat there.
Conformance
Section titled “Conformance”| Statement | Spec | Clause | reference_id |
|---|---|---|---|
The field’s current value is stored in the field dictionary V entry. | ISO 32000-2 | §12.7 | |
The default value is stored in the DV entry and is restored on form reset. | ISO 32000-2 | §12.7 | |
Field text formatting uses the default appearance string DA. | ISO 32000-2 | §12.7 |
NextPDF emits the AcroForm structure described by the cited clauses. It does not claim full ISO 32000-2 conformance.