PDF Tech

How to Create Custom Form Fields Using the Foxit PDF SDK for Web

by PDF SDK | August 8, 2022

The PDF format has become essential to modern software since it’s a good go-to solution for all types of documents. One way to create secure, editable, and easy-to-use PDFs for your business is to use Foxit. Foxit’s PDF SDK libraries offer plenty of features for various industries.

Web browser PDFs in particular have multiple use cases for document management. They’re an integral part of many banking systems for tasks like creating monthly statements, and the compliance industry also uses them for secure data collection and storage.

In this tutorial, you’ll learn how to use the Foxit PDF SDK for Web to create custom form fields in
your web browser PDF documents. You can follow along using this GitHub repository.

What Is the Foxit PDF SDK for Web?

The Foxit PDF SDK for Web—one of the many PDF SDKs provided by Foxit—is a batteries-included PDF library with all the advantages of Foxit’s rendering engine. Using the SDK, you can integrate a complete, fully customizable PDF viewer into your apps.

Web PDFs created through Foxit allow users to view, fill out, annotate, and sign documents in multiple languages through their mobile or desktop browser using JavaScript. The SDK works with all popular browsers, including Firefox, Safari, Chrome, and Opera.

To see how this works, you’re going to create a new PDF project from a template and use the SDK for Web to give it some structure.

Implementing the Foxit PDF SDK for Web

Start by downloading the Foxit PDF SDK for Web. The ZIP file should contain the SDK as well as documentation and additional examples.

To see what’s possible with the SDK, you can preview the examples by running an HTTP server from the unzipped directory:

bash
# NPX available with NPM v5.2 or newer
npx http-server

Setting Up the Project

This tutorial uses Vite for frontend tooling. It’s based on ES modules (ESM), fast, and comes with everything you need to use the SDK out of the box. To create a new project from a template and start the development server, make sure you’ve got Node.js version 12.2.0 or newer and run the following commands:

bash
npm create vite@latest project -- --template vanilla
cd project
npm install
npm run dev

Move the SDK into the created directory. For the rest of this tutorial, the SDK is assumed to be available at ./FoxitPDFSDKForWeb, relative to the parent project directory.

Loading the PDF

Before creating form fields, you need a PDF viewer with a loaded document to experiment with. To initialize the PDF viewer, first create the HTML structure and load the SDK:

html<!-- index.html -->
<!-- ... -->
<body>
<div class="container">
<div id="viewer"></div>
<div id="menu"></div>
</div>
<script src="./FoxitPDFSDKForWeb/lib/PDFViewCtrl.full.js"></script>
<script type="module" src="/main.js"></script>
</body>
<!-- ... -->

Additionally, in style.css, add some CSS to style the elements:

css
/* style.css */
html {
height: 100%;
}b
ody {
height: 100%;
margin: 0;
}.
container {
width: 100%;
height: 100%;
display: flex;
}#
viewer {
height: 100%;
flex: 1;
overflow: auto;
}#
menu {
width: 10rem;
}.
menu-element {
background: #f1f5f9;
padding: 1rem;
display: flex;
justify-content: center;
align-items: center;font-family: monospace;
margin: 0.5rem;
}

Inside main.js, use the SDK to create an instance of the pdfViewer:

javascript
import "./style.css";
const licenseSN = "...";
const licenseKey = "...";
const viewerContainer = document.getElementById("viewer");
const pdfViewer = new PDFViewCtrl.PDFViewer({
libPath: "./FoxitPDFSDKForWeb/lib",
jr: {
licenseSN,
licenseKey,
},
customs: {
ScrollWrap: PDFViewCtrl.CustomScrollWrap.create(viewerContainer),
},
});

You can find your values for licenseSN and licenseKey inside the ./FoxitPDFSDKForWeb/examples/license-key.js file.

The pdfViewer is created by providing the constructor with a configuration object containing:

* **libPath:** The relative path to the lib folder of the unzipped SDK package
* **jr:** Config options for the JR engine that include, most importantly, licensing information
* **customs.ScrollWrap:** A custom component that controls PDF sizing and scrolling, where
setting it adjusts the viewer to the container

With pdfViewer created, all you have to do is initialize it and load the document:

javascript
// ...
const loadPDF = async (url) => {
const response = await fetch(url);
const blob = await response.blob();return pdfViewer.openPDFByFile(blob);
};
pdfViewer.init(viewerContainer);
loadPDF("./FoxitPDFSDKForWeb/docs/FoxitPDFSDKforWeb_DemoGuide.pdf");

The above snippet fetches the PDF file as a blob and opens it in the viewer using its openPDFByFile() method. The PDF document used is a demo guide from the SDK’s included documentation.

The additional space on the right will serve as a menu for draggable form fields.

Creating Custom Form Fields

All you need to create a form field with the Foxit SDK is a viewer, the form field’s metadata (such as field type or select options), and the form field position. For this example, you’ll create a set of predefined form fields with ready metadata that the user can drag and drop into the viewer.

Defining Metadata

Start by defining the metadata for allowed fields, as well as additional helpers:

javascript
// ...
const menuContainer = document.getElementById("menu");
const randomId = () => `_${Math.random().toString(36).substring(2, 9)}`;
const FieldTypes = PDFViewCtrl.PDF.form.constant.Field_Type;
const formFields = [
{
label: "Push Button",
name: "push-button",
type: FieldTypes.PushButton,
width: 50,
height: 30,
},
{
label: "Checkbox",
name: "checkbox",
type: FieldTypes.CheckBox,
width: 50,height: 30,
},
{
label: "Radio Button",
name: "radio-button",
type: FieldTypes.RadioButton,
width: 80,
height: 30,
},
{
label: "Combo Box",
name: "combo-box",
type: FieldTypes.ComboBox,
width: 60,
height: 30,
},
{
label: "List Box",
name: "list-box",
type: FieldTypes.ListBox,
width: 60,
height: 100,
},
{
label: "Text",
name: "text",
type: FieldTypes.Text,
width: 60,
height: 30,
},
];
const comboBoxOptions = [
{ label: "10", value: "10", selected: true, defaultSelected: true },
{ label: "20", value: "20", selected: false, defaultSelected: false },
{ label: "30", value: "30", selected: false, defaultSelected: false },
{ label: "40", value: "40", selected: false, defaultSelected: false },
];
const listBoxOptions = comboBoxOptions;

The randomId() function will generate IDs to identify form fields within the document. FieldTypes is a shortcut for faster reference of predefined field types available in the SDK. Each form field entry contains:

* A label to inform the user about its use
* A name for matching dragged elements to the metadata entries
* A type to indicate the field’s type
* A width and `height` for calculating the position rectangle within the PDF

Lastly, comboBoxOptions and listBoxOptions contain sample options for fields that require users to select one.

Creating Drag and Drop Elements

With the metadata ready, you can create a function for handling the logic of drag and drop, as well as the form field placement:

javascript
// ...
const loadFormFieldsMenu = async (PDFDoc) => {
const PDFForm = await PDFDoc.loadPDFForm();
formFields.forEach((formField) => {
const element = document.createElement("div");
element.draggable = true;
element.id = formField.name;
element.classList.add("menu-element");
element.textContent = formField.label;
element.addEventListener("dragstart", (event) => {
event.dataTransfer.setData("text/plain", event.target.id);
});
menuContainer.append(element);
});
};

The function accepts PDFDoc—an SDK object representing a PDF document—as an argument. It’s used to retrieve a PDFForm object, which will be used to add and configure the form fields after those fields are processed into draggable elements and added to the side menu.

Each element has a draggable attribute set to true to allow for dragging, as well as an id corresponding to each form field’s unique name to match them with the underlying metadata. This id is later used inside the dragstart event listener to transfer it during the drag and drop action.

To get the PDFDoc parameter required for the loadFormFieldsMenu() function, you’ll have to get the resulting promise of the loadPDF() function by modifying it as below:

javascript
// ...
loadPDF("./FoxitPDFSDKForWeb/docs/FoxitPDFSDKforWeb_DemoGuide.pdf").then(
(PDFDoc) => {
loadFormFieldsMenu(PDFDoc);
}
);

With the menu items created, the app now looks like this:

Implementing Drag and Drop Functionality

Having created the draggable elements, it’s time to fully implement the drag and drop functionality and allow for creating form fields in the viewer:

javascript
// ...
const loadFormFieldsMenu = async (PDFDoc) => {
// ...
viewerContainer.addEventListener("dragover", (event) => {
event.preventDefault();
});
viewerContainer.addEventListener("drop", async (event) => {
event.preventDefault();
const droppedFormFieldName = event.dataTransfer.getData("text/plain");
const formField = formFields.find(
({ name }) => name === droppedFormFieldName
);
const pos = await pdfViewer.convertClientCoordToPDFCoord({
clientX: event.clientX,
clientY: event.clientY,
});
const id = randomId();await PDFForm.addControl(pos.index, id, formField.type, {
left: pos.left - formField.width / 2,
right: pos.left + formField.width / 2,
top: pos.top + formField.height / 2,
bottom: pos.top - formField.height / 2,
});
const field = PDFForm.getField(id);
if (formField.type === FieldTypes.ComboBox) {
field.setOptions(comboBoxOptions);
} else if (formField.type === FieldTypes.ListBox) {
field.setOptions(listBoxOptions);
}
});
};
// ...

In the above code, the dragover event listener forwards the interaction to be handled in the drop event by calling preventDefault().

Inside the drop event handler, the matching metadata is first retrieved using the dragged element’s data. Then, the mouse position from the event is transformed into PDF coordinates using the convertClientCoordToPDFCoord() method available on the pdfViewer instance.

The position, metadata, and randomly generated ID are used in the addControl() method call from the PDFForm object created earlier in the function. The method accepts the following arguments:

* The index of the page to place the form field at (retrieved from convertClientCoordToPDFCoord() call)
* The randomly generated ID for the newly created form field
* The type of the form field according to provided constants (retrieved from metadata)
* The argument that defines the placement for the form field in the form of a rectangle, calculated using width and height to make the mouse coordinates the form field’s center

Finally, in case the field accepts a list of options, it’s first accessed by the getField() method of the PDFForm object using the ID. The options are set accordingly using the setOptions() method.

The final app, with a few form fields already placed, looks like this:

Conclusion

Adding functionality to your PDFs can bring important benefits to your organization and your users. The ability to update and sign documents electronically saves time, money, and effort, and such customized, secure documents can increase trust in your company.

As you saw above, the multilingual PDF tool Foxit can easily help you achieve those goals. You can use the Foxit PDF SDK for Web to create custom form fields and implement drag and drop functionality. But that’s only the beginning of what it can do for you. If you want to learn more, consult the SDK’s official documentation and other resources to create the PDF functionality you want.

To check your work on this tutorial, see the GitHub repository.

Author: Arek Nawo