Blog Post

How to make a PDF fillable

Illustration: How to make a PDF fillable

A fillable PDF allows users to input information, such as names and dates, directly into PDFs, in turn enabling easy data capture and sharing. Creating fillable forms enhances workflow efficiency, especially for teams and customers in different locations. This tutorial will guide you through the process of creating a fillable PDF form using various methods — from free tools, to more advanced solutions.

Fillable PDFs offer significant advantages over traditional paper forms, such as ease of editing, organizing, and securely sharing data, eliminating the mess associated with paper forms.

1. Creating fillable PDFs using open source libraries

To create fillable PDFs, you’ll need software capable of defining interactive fields within a document. When exploring different options for creating fillable PDFs, there are various open source libraries that can be used, some of which are covered below.

PDF.js

PDF.js is a popular library developed by Mozilla for rendering PDF documents in web browsers. While it primarily focuses on rendering, it can create interactive forms by overlaying HTML input fields on the PDF canvas.

Step 1 — Setting up your HTML document

Create an HTML file that includes the PDF.js library and a canvas element to display the PDF:

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta
			name="viewport"
			content="width=device-width, initial-scale=1.0"
		/>
		<title>PDF.js Fillable Form</title>

		<style>
			#pdf-container {
				position: relative;
			}
			.input-field {
				position: absolute;
				border: 1px solid #000;
				background: rgba(255, 255, 255, 0.8);
			}
		</style>
	</head>
	<body>
		<div id="pdf-container">
			<canvas id="pdf-canvas"></canvas>
			<input
				type="text"
				class="input-field"
				style="left: 100px; top: 200px; width: 200px;"
				placeholder="Enter your name"
			/>
		</div>
		<script
			type="module"
			src="https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.mjs"
		></script>
	</body>
</html>

Step 2 — Rendering the PDF document

Include the following JavaScript to load and render the PDF:

<script type="module">
	import { GlobalWorkerOptions } from 'https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.min.mjs';
	GlobalWorkerOptions.workerSrc =
		'https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.worker.min.mjs';

	const url = 'document.pdf'; // Update with the path to your PDF

	const loadingTask = pdfjsLib.getDocument(url);
	loadingTask.promise.then((pdf) => {
		pdf.getPage(1).then((page) => {
			const viewport = page.getViewport({ scale: 1 });
			const canvas = document.getElementById('pdf-canvas');
			const context = canvas.getContext('2d');
			canvas.height = viewport.height;
			canvas.width = viewport.width;

			const renderContext = {
				canvasContext: context,
				viewport: viewport,
			};
			page.render(renderContext);
		});
	});
</script>
  • This code initializes PDF.js, loads the specified PDF, and renders the first page onto a canvas element. You can overlay input fields at specified positions to allow users to fill in information, but note that managing these inputs may require additional handling for focus and events.

While PDF.js can be used to overlay input fields on rendered PDFs, consider the complexity and user experience. For more sophisticated fillable PDF creation, libraries like pdf-lib, PDFKit, or Nutrient may offer better functionality and ease of use.

pdf-lib

pdf-lib is a versatile library for creating and modifying PDF documents, and it works seamlessly in both Node.js and browser environments.

Step 1 — Installing pdf-lib

If you’re using Node.js, install pdf-lib via npm:

npm install pdf-lib

Step 2 — Filling an existing PDF form

Use the following code to populate fields in an existing PDF:

import { PDFDocument } from 'pdf-lib';
import fs from 'fs';

async function fillPdf() {
	// Load an existing PDF.
	const existingPdfBytes = fs.readFileSync('sample_pdf.pdf');
	const pdfDoc = await PDFDocument.load(existingPdfBytes);
	const form = pdfDoc.getForm();

	// Fill form fields.
	const nameField = form.getTextField('Name'); // Ensure this matches the field name in your PDF.
	nameField.setText('John Doe'); // Fill in the field.

	// Serialize the PDF document to bytes.
	const pdfBytes = await pdfDoc.save();
	fs.writeFileSync('filled.pdf', pdfBytes);
}

fillPdf();

You can download this sample PDF file to try the script.

  • This script loads an existing PDF file, accesses the form fields, populates them with specified values, and saves the filled PDF as filled.pdf.

PDFKit

PDFKit is a powerful and flexible library for creating complex PDF documents in Node.js. It allows developers to generate PDFs programmatically, enabling the addition of text, images, vector graphics, and even interactive form fields. This versatility makes PDFKit an excellent choice for generating invoices, reports, and any documents that require a structured layout. By using PDFKit, you can customize your PDFs extensively, tailoring them to your specific requirements.

Step 1 — Installing PDFKit

If you’re using Node.js, install PDFKit via npm:

npm install pdfkit

Step 2 — Creating a fillable PDF form

You can create a PDF with fillable fields using the following code:

import PDFDocument from 'pdfkit';
import fs from 'fs';

// Create a new PDF document.
const doc = new PDFDocument();

// Pipe the PDF into a writable stream.
doc.pipe(fs.createWriteStream('fillable.pdf'));

// Add a title.
doc.fontSize(25).text('Fillable PDF Form', { align: 'center' });
doc.moveDown();

// Add text for the name field.
doc.fontSize(12).text('Name:', { continued: true });
doc.rect(100, 100, 200, 20).stroke(); // Draw a rectangle for the text field.
doc.text('', 100, 100, { width: 200, height: 20 }); // Placeholder text.

// Add text for the email field.
doc.moveDown(30);
doc.fontSize(12).text('Email:', { continued: true });
doc.rect(100, 150, 200, 20).stroke(); // Draw a rectangle for the text field.
doc.text('', 100, 150, { width: 200, height: 20 }); // Placeholder text.

// Finalize the PDF and end the stream.
doc.end();

This script generates a new PDF document named fillable.pdf. It includes a title and two fields where users can input their name and email. While the fields are visually represented, keep in mind that they aren’t true interactive form fields. Users can fill them out in a PDF viewer, making this a practical solution for many applications.

2. Creating advanced fillable PDFs using Nutrient (previously PSPDFKit)

Nutrient Web SDK provides a comprehensive JavaScript library for generating, customizing, and managing versatile and efficient PDF forms programmatically. This section covers how to create various form fields and customize them.

Explore the Nutrient demo

Prerequisites

  • Ensure you have a valid Nutrient license with Form Creator support (version 2019.5 or newer) for creating form fields. For adding form fields using the UI, you’ll need version 2022.3 or later.

  1. Setting up Nutrient Web SDK

  • First, install Nutrient:

npm install pspdfkit
  • Copy the distribution files to your project’s assets:

cp -R ./node_modules/pspdfkit/dist/ ./assets/
  1. Loading Nutrient

  • Add an HTML container where Nutrient will be rendered:

<div id="pspdfkit" style="width: 100%; height: 100vh;"></div>
  • In your HTML file, add a <script> tag to load your main JavaScript file:

<script src="index.js" type="module"></script>
  • Initialize Nutrient in JavaScript:

import './assets/pspdfkit.js';

const baseUrl = `${window.location.protocol}//${window.location.host}/assets/`;

PSPDFKit.load({
	baseUrl,
	container: '#pspdfkit',
	document: 'document.pdf',
})
	.then((instance) => {
		console.log('PSPDFKit loaded', instance);
	})
	.catch((error) => {
		console.error(error.message);
	});
  1. Creating a text form field

  • Use PSPDFKit.Annotations.WidgetAnnotation for the widget and PSPDFKit.FormFields.TextFormField for the 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 textFormField = new PSPDFKit.FormFields.TextFormField({
	name: 'MyTextFormField',
	annotationIds: new PSPDFKit.Immutable.List([widget.id]),
	value: 'Text shown in the form field',
});

instance.create([widget, textFormField]);
  1. Creating radio buttons

  • Create multiple widgets with the same form field name:

const radioWidget1 = new PSPDFKit.Annotations.WidgetAnnotation({
	id: PSPDFKit.generateInstantId(),
	pageIndex: 0,
	formFieldName: 'MyRadioField',
	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: 'MyRadioField',
	boundingBox: new PSPDFKit.Geometry.Rect({
		left: 130,
		top: 100,
		width: 20,
		height: 20,
	}),
});
const radioFormField = new PSPDFKit.FormFields.RadioButtonFormField({
	name: 'MyRadioField',
	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, radioFormField]);
  1. Updating form fields

  • Update fields using instance.update(), and delete them using instance.delete(), if necessary.

  1. Enabling form design mode

  • Set the form design mode to allow users to adjust the placement of form elements:

instance.setViewState((viewState) =>
	viewState.set('formDesignMode', true),
);
  1. Serving the project

  • Use the serve package to host your app:

yarn global add serve
serve -l 8080 .
  • Access the app at http://localhost:8080.

This is the complete script for your reference:

import './assets/pspdfkit.js';

const baseUrl = `${window.location.protocol}//${window.location.host}/assets/`;

PSPDFKit.load({
	baseUrl,
	container: '#pspdfkit',
	document: 'document.pdf',
})
	.then((instance) => {
		console.log('PSPDFKit loaded', instance);

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

		instance.create([widget, textFormField]);

		// Create radio button form field with two options.
		const radioWidget1 = new PSPDFKit.Annotations.WidgetAnnotation({
			id: PSPDFKit.generateInstantId(),
			pageIndex: 0,
			formFieldName: 'MyRadioField',
			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: 'MyRadioField',
			boundingBox: new PSPDFKit.Geometry.Rect({
				left: 130,
				top: 100,
				width: 20,
				height: 20,
			}),
		});
		const radioFormField = new PSPDFKit.FormFields.RadioButtonFormField(
			{
				name: 'MyRadioField',
				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, radioFormField]);

		// Enable form design mode.
		instance.setViewState((viewState) =>
			viewState.set('formDesignMode', true),
		);
	})
	.catch((error) => {
		console.error('Error loading PSPDFKit:', error.message);
	});

Comparison of fillable PDF creation tools

When considering options for creating fillable PDFs, it’s essential to evaluate the functionality, usage, and limitations of each tool. Below is a comparison of popular free tools and Nutrient.

1. Free tools for creating fillable PDFs

PDF.js

  • Functionality— PDF.js is an open source JavaScript library developed by Mozilla, primarily designed for rendering PDF documents directly in web browsers. Although its main purpose is to display PDFs, it provides limited functionality for creating interactive forms by overlaying HTML input elements onto the PDF canvas.

  • Usage — To use PDF.js, developers need to set up an HTML file that includes the library and a canvas element for rendering. They can then manually overlay HTML form elements to simulate fillable fields, which requires custom coding and positioning.

  • Limitations — PDF.js doesn’t natively support the creation of fillable fields, meaning developers must handle input field placement and management through additional HTML and JavaScript code. This approach can become complex and may not provide a seamless user experience.

pdf-lib

  • Functionalitypdf-lib is a versatile and powerful JavaScript library that enables developers to create, modify, and fill PDF documents in both browser and Node.js environments. It provides a straightforward API that simplifies the process of adding interactive form fields and populating them with data.

  • Usage — Developers can easily install pdf-lib via npm and use its methods to create new PDFs or manipulate existing ones. The library allows users to add form fields, such as text fields, checkboxes, and radio buttons, and fill them out programmatically with specified values.

  • Limitations — While pdf-lib is highly flexible and feature-rich, utilizing its more advanced capabilities may require a deeper understanding of PDF document structures. For simple projects, this complexity might be unnecessary, leading to a steeper learning curve for new users.

PDFKit

  • Functionality — PDFKit is a robust library for generating complex PDF documents using Node.js. It supports various features, including the ability to add text, images, and interactive form fields, making it suitable for creating sophisticated fillable PDFs.

  • Usage — Developers can install PDFKit via npm and leverage its extensive API to create new PDF files with fillable fields. The library offers a straightforward way to define field properties and customize the layout of a PDF.

  • Limitations — While PDFKit excels in document creation, it doesn’t provide functionalities for loading and modifying existing PDF files. This limitation may restrict its use in scenarios where existing PDFs need to be updated or filled out.

2. Comparison with Nutrient

  • Functionality — Nutrient (formerly PSPDFKit) provides a comprehensive set of advanced features for working with PDFs, including the ability to create and manage fillable forms, perform form validation, and extract data efficiently. It also offers a rich user interface and extensive customization options.

  • Usage — Nutrient typically requires integration into larger applications or systems, offering a more complete solution for PDF management. Its extensive documentation and support make it easier for developers to implement complex PDF functionalities.

  • Limitations — While Nutrient provides a powerful set of tools, it may come with licensing costs, which could be a consideration for smaller projects or individual developers looking for budget-friendly solutions.

Hopefully this comparison helps in determining which tool best suits your project needs based on functionality, ease of use, and specific requirements for creating fillable PDFs.

Best practices for creating a fillable PDF

Below are some best practices for creating a fillable PDF.

  1. Use a clear and consistent layout — A well-organized layout makes your form easy to read and navigate.

  2. Use clear and concise language — Ensure your form labels and instructions are straightforward and easy to understand.

  3. Use headings and subheadings — Organize your form with headings and subheadings to make it easy to scan.

  4. Use bullet points and numbered lists — These elements can make your form easier to read and follow.

  5. Ensure form fields are large enough — Make sure form fields are adequately sized for users to enter their information comfortably.

  6. Clearly label the submit button — The submit button should be easy to find and clearly labeled to guide users through the submission process.

  7. Test your form — Ensure your form is working correctly and that users can easily complete and submit it.

By adhering to these best practices, you can create effective and user-friendly fillable PDFs.

Conclusion

In conclusion, creating fillable PDFs can be accomplished through various methods, ranging from free libraries, to advanced solutions like Nutrient. The choice of tool depends on your specific needs, such as the complexity of the form and ease of use. For a seamless experience and robust features, we recommend trying out a demo of Nutrient. For further assistance, don’t hesitate to contact our Sales team.

FAQ

Here are a few frequently asked questions about fillable PDFs.

What are fillable PDFs?

Fillable PDFs are documents that allow users to enter information directly into designated fields, making data entry easier and more efficient.

Why should I use fillable PDFs instead of traditional forms?

Fillable PDFs enhance workflow efficiency by allowing easy data capture and sharing, reducing the hassle associated with paper forms.

What tools can I use to create fillable PDFs?

You can create fillable PDFs using various tools, including open source libraries like pdf-lib and PDFKit, or commercial solutions like Nutrient (formerly PSPDFKit).

Can I create fillable PDFs using JavaScript?

Yes, you can create fillable PDFs using JavaScript libraries such as pdf-lib and Nutrient, which provide functionality for adding interactive form fields.

Are there any limitations to creating fillable PDFs?

Some libraries may have limitations in terms of features or ease of use, requiring custom coding for field management or a deeper understanding of PDF structures for advanced functionalities.

Author
Hulya Masharipov Technical Writer

Hulya is a frontend web developer and technical writer at Nutrient who enjoys creating responsive, scalable, and maintainable web experiences. She’s passionate about open source, web accessibility, cybersecurity privacy, and blockchain.

Explore related topics

Related products
Share post
Free trial Ready to get started?
Free trial