Create Fillable PDF Forms Using JavaScript

Since version 2019.5, PSPDFKit for Web has included support for programmatically creating and removing form fields from a document, provided the license includes the Form Creator component (formerly Form Designer). As of version 2022.3, it’s also possible to create form fields using the built-in user interface.

A form field is a model representation of a visual form in a document. To create a form field, you have to first create the form element (also known as a widget annotation). For more information on the difference between a form field and a form element, please refer to our introduction to forms guide.

Make sure to create a form field together with its associated widget annotation, since widget annotations that don’t have a matching form field can’t be created. Since the form field requires a widget annotation ID when created, you’ll need to generate a unique ID for your widget annotation via PSPDFKit#generateInstantId(). You can then add both the widget annotation and the form field to the document via PSPDFKit.Instance#create().

You can add any kind of form field to a document. For more information about the available form field types, check out the PSPDFKit.FormFields documentation.

If you need to allow widget annotations to be moved or resized through the UI, set the PSPDFKit.ViewState#formDesignMode property to true.

Adding a Text Form Field

The following example consolidates both creating the widget annotation and a TextFormField:

// Create a new text form field.
const widget = new PSPDFKit.Annotations.WidgetAnnotation({
  id: PSPDFKit.generateInstantId(),
  pageIndex: 0,
  formFieldName: "MyFormField",
  boundingBox: new PSPDFKit.Geometry.Rect({
    left: 100,
    top: 75,
    width: 200,
    height: 80
  })
});
const formField = new PSPDFKit.FormFields.TextFormField({
  name: "MyFormField",
  annotationIds: new PSPDFKit.Immutable.List([widget.id]),
  value: "Text shown in the form field"
});

instance.create([widget, formField]);

It’s important to specify the formFieldName property on the widget annotation to link it to the name property of the corresponding form field that, in the case of the former example, is created together with the widget annotation. Likewise, the annotationIds property of the form field needs to be properly set with a PSPDFKit.Immutable.List of widget annotations linked to it.

Adding Radio Buttons and Checkboxes

PSPDFKit.FormFields.RadioButtonFormField and PSPDFKit.FormFields.CheckBoxFormField may use more than a single widget annotation to represent the different available form field values. The current form field value can be retrieved from PSPDFKit.FormFields.FormField#value for any form field type, except for PSPDFKit.FormFields.SignatureFormField:

// Create two radio buttons and position them in the document.
// Note that both widget annotations have the same `formFieldName` value.
const radioWidget1 = new PSPDFKit.Annotations.WidgetAnnotation({
  id: PSPDFKit.generateInstantId(),
  pageIndex: 0,
  formFieldName: "MyFormField",
  boundingBox: new PSPDFKit.Geometry.Rect({
    left: 100,
    top: 100,
    width: 20,
    height: 20
  })
});
const radioWidget2 = new PSPDFKit.Annotations.WidgetAnnotation({
  id: PSPDFKit.generateInstantId(),
  pageIndex: 0,
  formFieldName: "MyFormField",
  boundingBox: new PSPDFKit.Geometry.Rect({
    left: 130,
    top: 100,
    width: 20,
    height: 20
  })
});
const formField = new PSPDFKit.FormFields.RadioButtonFormField({
  name: "MyFormField",
  annotationIds: new PSPDFKit.Immutable.List([
    radioWidget1.id,
    radioWidget2.id
  ]),
  options: new PSPDFKit.Immutable.List([
    new PSPDFKit.FormOption({
      label: "Option 1",
      value: "1"
    }),
    new PSPDFKit.FormOption({
      label: "Option 2",
      value: "2"
    })
  ]),
  defaultValue: "1"
});
instance.create([radioWidget1, radioWidget2, formField]);

Adding Combo and List Boxes

PSPDFKit.FormFields.ComboBoxFormField and PSPDFKit.FormFields.ListBoxFormField allow you to select a value from multiple choices. The possible choices can be specified in the options property, and initially selected values can be set on the values property. They’re available to both form field types since they inherit from PSPDFKit.FormFields.ChoiceFormField:

const widget = new PSPDFKit.Annotations.WidgetAnnotation({
  id: PSPDFKit.generateInstantId(),
  pageIndex: 0,
  formFieldName: "MyFormField",
  boundingBox: new PSPDFKit.Geometry.Rect({
    left: 100,
    top: 75,
    width: 150,
    height: 60
  })
});
const formField = new PSPDFKit.FormFields.ComboBoxFormField({
  name: "MyFormField",
  annotationIds: new PSPDFKit.Immutable.List([widget.id]),
  values: new PSPDFKit.Immutable.List(["orange"]), // initially selected value(s)
  options: new PSPDFKit.Immutable.List([
    // Available values.
    new PSPDFKit.FormOption({ label: "Apple", value: "apple" }),
    new PSPDFKit.FormOption({ label: "Banana", value: "banana" }),
    new PSPDFKit.FormOption({ label: "Orange", value: "orange" })
  ])
});
instance.create([widget, formField]);

Updating Form Fields and Widget Annotations

To update a form field or widget annotation, you can use the PSPDFKit.Instance#update() method. You can also use it to change the widget annotations associated with the form field.

Removing Form Fields and Widget Annotations

You can easily remove any form field from a document using PSPDFKit.Instance#delete(). This call will also remove the associated widget annotations.

Editing Widget Annotations through the UI

The UI will allow each form field present on the current document page — regardless of if it was originally present on the document or if it was added using the programmatic API as outlined in this guide — to be fillable by users.

If you want to allow your users to adjust the placement of the form elements or resize them, you’ll have to activate the form design mode.

You can do this by setting the PSPDFKit.ViewState#formDesignMode property to true:

// During initialization.
PSPDFKit.load({
  // Your configuration.
  initialViewState: new PSPDFKit.ViewState({ formDesignMode: true })
});

// Or after an instance has been created.
instance.setViewState((viewState) =>
  viewState.set("formDesignMode", true)
);