Editing PDF form fields
Use form field editing to control validation and behavior in PDF workflows.
Common use cases include:
- Setting fields to read-only after approval
- Marking fields as required for validation
- Reading default values for reset logic
- Navigating parent-child field hierarchies
- Accessing widgets for appearance-related workflows
How Nutrient helps
Nutrient Java SDK handles form field structures, property updates, and hierarchy traversal.
The SDK handles:
- Parsing form field dictionaries and annotation widget references
- Managing field hierarchy traversal and parent-child relationships
- Handling field flag bit manipulation for read-only and required properties
- Complex widget annotation access and appearance state management
Complete implementation
This example updates form field properties and inspects field hierarchy:
package io.nutrient.Sample;
import io.nutrient.sdk.Document;import io.nutrient.sdk.editors.PdfEditor;import io.nutrient.sdk.editors.pdf.formfields.PdfFormFieldCollection;import io.nutrient.sdk.editors.pdf.formfields.PdfFormField;import io.nutrient.sdk.editors.pdf.annotations.PdfWidgetAnnotation;import io.nutrient.sdk.enums.PdfFormFieldType;
public class EditingPdfFormFields {Create the main method as the sample entry point:
public static void main(String[] args) {Opening a document with form fields
Open the form document with try-with-resources, create an editor, and get the form field collection.
The collection supports iteration and lookup across field types:
try (Document document = Document.open("input_forms.pdf")) { PdfEditor editor = PdfEditor.edit(document); PdfFormFieldCollection formFields = editor.getFormFieldCollection();Inspecting field properties
Iterate over fields and inspect key properties.
This sample prints:
- Name and full name
- Field type
- Terminal/parent status
- Read-only and required flags
- Current and default values
for (PdfFormField field : formFields) { System.out.println("Name: " + field.getName()); System.out.println("FullName: " + field.getFullName()); System.out.println("FieldType: " + field.getFieldType()); System.out.println("IsTerminal: " + field.getIsTerminal()); System.out.println("IsReadOnly: " + field.getIsReadOnly()); System.out.println("IsRequired: " + field.getIsRequired()); System.out.println("Value: " + field.getValue()); System.out.println("DefaultValue: " + field.getDefaultValue()); System.out.println("---"); }Making a field read-only
Find a field by full name and set it to read-only.
In this sample, Text1 is locked with setIsReadOnly(true):
PdfFormField textField = formFields.findByFullName("Text1"); if (textField != null) { textField.setIsReadOnly(true); }Making a field required
Find a field by full name and mark it as required.
In this sample, Name is marked required with setIsRequired(true):
PdfFormField nameField = formFields.findByFullName("Name"); if (nameField != null) { nameField.setIsRequired(true); }Reading a default value
Read a field’s default value for reset and change-tracking logic.
In this sample:
getValue()returns the current value.getDefaultValue()returns the reset value.
PdfFormField countryField = formFields.findByFullName("Dropdown1"); if (countryField != null) { String defaultValue = countryField.getDefaultValue(); System.out.println("Default value: " + defaultValue); }Working with field hierarchy
Traverse field hierarchies by checking the terminal status.
For non-terminal fields:
getChildCount()returns the child count.getChild(i)retrieves each child.
Full names commonly use dot notation — for example, Address.Street:
for (PdfFormField field : formFields) { if (!field.getIsTerminal()) { int childCount = field.getChildCount(); System.out.println("Parent field '" + field.getName() + "' has " + childCount + " children:"); for (int i = 0; i < childCount; i++) { PdfFormField child = field.getChild(i); System.out.println(" - Child: " + child.getName()); } } }Accessing widget annotations
Access widget annotations for terminal fields.
In this sample:
getWidgetCount()returns the widget count.getWidget(i)returns a widget by index.
Fields can have more than one widget across pages:
for (PdfFormField field : formFields) { if (field.getIsTerminal()) { int widgetCount = field.getWidgetCount(); System.out.println("Field '" + field.getName() + "' has " + widgetCount + " widget(s)"); for (int i = 0; i < widgetCount; i++) { PdfWidgetAnnotation widget = field.getWidget(i); // Access widget properties for appearance customization } } }Batch updating field properties
Apply batch updates by field type.
In this sample:
- Text fields are marked required.
- Signature fields are set to read-only.
Use this pattern for workflow-driven form policies:
for (PdfFormField field : formFields) { if (field.getIsTerminal()) { // Make all text fields required if (field.getFieldType() == PdfFormFieldType.Text) { field.setIsRequired(true); }
// Make all signature fields read-only until other fields are filled if (field.getFieldType() == PdfFormFieldType.Signature) { field.setIsReadOnly(true); } } }Saving the modified form
Save the output PDF and close the editor:
editor.saveAs("output.pdf"); editor.close(); } catch (Exception e) { System.err.println("Error: " + e.getMessage()); e.printStackTrace(); } }}Conclusion
Use this workflow to edit PDF form fields:
- Open the document using try-with-resources for automatic resource cleanup.
- Create a PDF editor and retrieve the form field collection.
- Iterate through all form fields to inspect properties and field types.
- Access field properties, including name, full name, field type, terminal status, read-only flag, required flag, current value, and default value.
- Set fields to read-only using
setIsReadOnly(true)to prevent user modifications. - Mark fields as required using
setIsRequired(true)for validation enforcement. - Read default values using
getDefaultValue()for form reset operations. - Navigate hierarchical field structures using
getIsTerminal(),getChildCount(), andgetChild(). - Access widget annotations from terminal fields using
getWidgetCount()andgetWidget(). - Implement batch updates by iterating fields and applying conditional logic based on field type.
- Use
findByFullName()to locate specific fields by their hierarchical names. - Save and close the editor to persist field property changes.
For related form workflows, refer to the Java SDK guides.