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
- Traversing parent-child field hierarchies
- Accessing widgets for appearance updates
How Nutrient helps
Nutrient Python SDK handles form field dictionaries, property updates, and hierarchy traversal.
The SDK handles:
- PDF form field dictionaries and annotation structures
- Recursive hierarchy traversal for parent-child fields
- Flag manipulation at the byte level
- Low-level widget access for appearance customization
Complete implementation
This example edits multiple form field properties in one pass:
from nutrient_sdk import Documentfrom nutrient_sdk import PdfEditorfrom nutrient_sdk import PdfFormFieldTypefrom nutrient_sdk import NutrientExceptionCreate the main function:
def main():Opening a document with form fields
Open the PDF in a context manager(opens in a new tab) so resources are cleaned up after processing.
Then call get_form_field_collection() to access:
- Terminal fields (leaf fields with values)
- Non-terminal fields (parent fields with children)
try: with Document.open("input_forms.pdf") as document: editor = PdfEditor.edit(document) form_fields = editor.get_form_field_collection()Inspecting field properties
Iterate over fields to inspect key properties.
This sample reads:
- Field name and full name
- Field type
- Terminal/parent state
- Read-only and required flags
- Current value and default value
Use this step for form auditing and validation setup.
for field in form_fields: print(f"Name: {field.get_name()}") print(f"FullName: {field.get_full_name()}") print(f"FieldType: {field.get_field_type()}") print(f"IsTerminal: {field.get_is_terminal()}") print(f"IsReadOnly: {field.get_is_read_only()}") print(f"IsRequired: {field.get_is_required()}") print(f"Value: {field.get_value()}") print(f"DefaultValue: {field.get_default_value()}") print("---")Making a field read-only
Find a field by full name and set it to read-only.
In this sample, Text1 is locked with set_is_read_only(True). If Text1 doesn’t exist in your input file, find_by_full_name() returns None and no update is applied.
text_field = form_fields.find_by_full_name("Text1") if text_field is not None: text_field.set_is_read_only(True)Making a field required
Find a field by full name and mark it as required.
In this sample, Check1 is marked required with set_is_required(True). If Check1 isn’t present in your input form, this lookup performs no operation.
check_field = form_fields.find_by_full_name("Check1") if check_field is not None: check_field.set_is_required(True)Reading a default value
Read a field’s default value for reset and change-tracking logic.
In this sample:
get_value()returns the current value.get_default_value()returns the reset value.
If Dropdown1 isn’t present in your input form, the lookup returns None and the sample skips this read.
country_field = form_fields.find_by_full_name("Dropdown1") if country_field is not None: default_value = country_field.get_default_value() print(f"Default value: {default_value}")Working with field hierarchy
Traverse field hierarchies by checking whether a field is terminal.
For non-terminal fields, use:
get_child_count()to read child count.get_child(i)to access each child.
Full names often use dot notation, for example Address.Street:
for field in form_fields: if not field.get_is_terminal(): child_count = field.get_child_count() print(f"Parent field '{field.get_name()}' has {child_count} children:") for i in range(child_count): child = field.get_child(i) print(f" - Child: {child.get_name()}")Accessing widget annotations
Access widgets for terminal fields to inspect or update visual presentation.
In this sample:
get_widget_count()returns the number of widgets.get_widget(i)returns a widget by index.
A field can have one or more widgets across pages:
for field in form_fields: if field.get_is_terminal(): widget_count = field.get_widget_count() print(f"Field '{field.get_name()}' has {widget_count} widget(s)") for i in range(widget_count): widget = field.get_widget(i) # Access widget properties for appearance customizationBatch updating field properties
Apply updates to multiple fields using type-based conditions.
In this sample:
- Text fields are marked required.
- Signature fields are set to read-only.
Use this pattern for workflow-driven form rules:
get_field_type()returns an integer value. In that case, compare against enum values (for example,PdfFormFieldType.TEXT.valueandPdfFormFieldType.SIGNATURE.value) instead of enum objects.
for field in form_fields: if field.get_is_terminal(): # Make all text fields required if field.get_field_type() == PdfFormFieldType.TEXT: field.set_is_required(True)
# Make all signature fields read-only until other fields are filled if field.get_field_type() == PdfFormFieldType.SIGNATURE: field.set_is_read_only(True)Saving the modified form
Save the output PDF and close the editor:
editor.save_as("output.pdf") editor.close() except NutrientException as e: print(f"Error: {e}")
if __name__ == "__main__": main()Conclusion
Use this workflow to edit form field properties:
- Open the document using a context manager(opens in a new tab) for automatic resource cleanup.
- Create an editor and access the form field collection with
get_form_field_collection(). - The form field collection provides iteration and lookup operations for all fields in the document.
- Inspect field properties using method calls:
get_name(),get_full_name(),get_field_type(),get_is_terminal(),get_is_read_only(),get_is_required(),get_value(), andget_default_value(). - Fully qualified names use dot-notation for hierarchical fields (e.g.
"Address.Street"). - Set fields to read-only with
find_by_full_name()andset_is_read_only(True)to lock fields after workflow milestones. - Mark fields as required with
set_is_required(True)to enforce validation, preventing form submission until values are provided. - Read default values with
get_default_value()for reset operations and change detection. - Navigate field hierarchy with
get_is_terminal(),get_child_count(), andget_child(i)for parent-child relationships. - Access widget annotations with
get_widget_count()andget_widget(i)for appearance customization. - Batch update properties by iterating terminal fields and applying conditional logic based on
get_field_type()comparisons. - Save the document with
save_as()to persist all property modifications.
Sample field names such as
Text1,Check1, andDropdown1are illustrative. If those names don’t exist in your input PDF, those targeted operations are safely skipped.
For related form workflows, refer to the Python SDK editor guides.