Blog Post

Vue.js PDF Editor: How to Edit PDFs Using Vue.js

Illustration: Vue.js PDF Editor: How to Edit PDFs Using Vue.js

In this article, you’ll learn how to edit and manipulate PDF files using PSPDFKit’s Vue.js PDF library. You’ll create an end-to-end project using Vue.js and the PSPDFKit SDK that will merge, rotate, remove, and add pages in PDF files.

Use Cases for Editing PDFs in Vue.js

There are a few reasons you might need a JavaScript-based PDF editing library. For one, you can use it to allow your users to view and edit PDFs straight in the browser or your app. This ensures they don’t need to have a PDF editor installed locally and provides a consistent PDF editing user interface (UI) for all users.

Additionally, you might want to integrate certain PDF editing and automation features into your web application that simply aren’t available in desktop software. For instance, you can provide your users with a single button that merges two PDFs and crops or rotates the final output.

Vue.js PDF Editor — Build or Buy

Once you decide you’d like to integrate a JavaScript-based PDF editor into your application, you’ll need to look at the available options. Currently, there isn’t a full-featured Vue.js open source solution available. One option is to create a custom JavaScript-based PDF editor from scratch, but that will likely take a considerable amount of time and effort. If you need a quick solution, you can leverage an existing SDK such as PSPDFKit. We offer a full-featured editor with superb support and wide industry adoption. It supports React, Vue.js, and a whole host of additional platforms and frameworks.

Setting Up Vue.js and PSPDFKit

Our documentation outlines how to set up Vue.js and PSPDFKit. This post will walk through the process, but it’s worth checking out the documentation on your own to see for yourself what else is possible with PSPDFKit.

Make sure you have the latest version of Node.js installed. You can download and install Node.js via the official website if you don’t have it.

You’ll also need access to either Yarn or npm. This post uses Yarn, but you can use npm instead if you prefer.

The first step is to install Vue.js:

yarn global add @vue/cli

Next, create a new project using Vue.js:

vue create pspdfkit-vue-demo

Make sure you run the vue create command in the folder where you want your project to be. Pick Vue 3 as your preset, and select Yarn as the package manager:

Vue CLI v5.0.8
? Please pick a preset: Default ([Vue 3] babel, eslint)
? Pick the package manager to use when installing dependencies: Yarn

Now, go to the new project directory and add PSPDFKit as a dependency:

cd pspdfkit-vue-demo
yarn add pspdfkit

Copy the PSPDFKit for Web library assets from ./node_modules/pspdfkit/dist/pspdfkit-lib to the public/js directory:

mkdir -p public/js
cp -R ./node_modules/pspdfkit/dist/pspdfkit-lib public/js/pspdfkit-lib

Finally, do a dry run to ensure your default Vue.js application is working fine. To fire up the development server, run this command:

yarn serve

If you open the URL that shows up in the terminal, you’ll see the default Vue.js, as shown below.

Default Vue.js page

So far, so good!

Now, copy a default PDF file to the public folder. Download this demo PDF file and move it to the public folder. Then you’ll be ready to start writing some PSPDFKit-specific code and open the demo PDF in the PSPDFKit viewer.

At this point, your directory structure will look something like this:

├── README.md
├── babel.config.js
├── jsconfig.json
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── js
│   │   └── pspdfkit-lib
│   │       ├── Caveat-Bold.woff
│   │       ├── ...
│   │       ├── pspdfkit-eb1f893073cadb44.wasm
│   │       └── windows-ba2e2d3f7c5061a9.css
│   └── pspdfkit-web-demo.pdf
├── node_modules
│   └── ...
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   └── main.js
├── vue.config.js
└── yarn.lock

Opening the Demo PDF Using PSPDFKit

Create a new PSPDFKitContainer.vue file in the src/components directory and add the following code to it:

<template>
	<div class="pdf-container"></div>
</template>

<script>
	import PSPDFKit from 'pspdfkit';

	/**
	 * PSPDFKit for Web example component.
	 */
	export default {
		name: 'PSPDFKit',
		/**
		 * The component receives `pdfFile` as a prop, which is of type `String` and is required.
		 */
		props: {
			pdfFile: {
				type: String,
				required: true,
			},
		},
		/**
		 * We wait until the template has been rendered to load the document into the library.
		 */
		mounted() {
			this.loadPSPDFKit().then((instance) => {
				this.$emit('loaded', instance);
			});
		},
		/**
		 * We watch for `pdfFile` prop changes and trigger unloading and loading when there's a new document to load.
		 */
		watch: {
			pdfFile(val) {
				if (val) {
					this.loadPSPDFKit();
				}
			},
		},
		/**
		 * Our component has the `loadPSPDFKit` method. This unloads and cleans up the component and triggers document loading.
		 */
		methods: {
			async loadPSPDFKit() {
				PSPDFKit.unload('.pdf-container');
				return PSPDFKit.load({
					// Access the `pdfFile` from props.
					document: this.pdfFile,
					container: '.pdf-container',
				});
			},
		},

		/**
		 * Clean up when the component is unmounted so it's ready to load another document (not needed in this example).
		 */
		beforeUnmount() {
			PSPDFKit.unload('.pdf-container');
		},
	};
</script>

<style scoped>
	.pdf-container {
		height: 100vh;
	}
</style>

This file is taken from the Vue.js getting started guide. It defines a new template that contains a div with the pdf-container class. The PSPDFKit UI and the PDF will be loaded inside this div. The component also expects a pdfFile prop that will contain the path to the PDF file PSPDFKit is supposed to open.

The component defines a loadPSPDFKit method. It unloads a PSPDFKit instance if already loaded, and then reloads it inside the .pdf-container div with the pdfFile prop value.

The component also defines the mounted and beforeUnmount lifecycle hooks. The mounted hook runs the loadPSPDFKit method and emits the loaded event upon successful return. The beforeUnmount hook makes sure the PSPDFKit instance is safely unloaded before the component is unmounted. You’ll handle the loaded event later on.

The component also contains a watcher that reloads PSPDFKit whenever the pdfFile prop value changes. This is important to ensure a prop value change triggers a reinitialization of PSPDFKit.

There’s also a scoped style defined inside the component. The style sets the height of the .pdf-container to 100vh. This is required so that PSPDFKit knows how much space it’s allowed to take. By default, the container has no height, and if the height isn’t set, PSPDFKit will fail to load and will throw this error:

Uncaught (in promise) PSPDFKitError: The mounting container has no height.

Now, with the custom PSPDFKit component defined, you need to reference this component inside your App.vue file and load it. To do that, replace everything in the App.vue file with this:

<template>
	<div id="app">
		<label for="file-upload" class="custom-file-upload">
			Open PDF
		</label>
		<input
			id="file-upload"
			type="file"
			@change="openDocument"
			class="btn"
		/>
		<PSPDFKitContainer :pdfFile="pdfFile" @loaded="handleLoaded" />
	</div>
</template>

<script>
import PSPDFKitContainer from '@/components/PSPDFKitContainer';

export default {
	data() {
		return {
			pdfFile: this.pdfFile || '/pspdfkit-web-demo.pdf',
		};
	},
	/**
	 * Render the `PSPDFKitContainer` component.
	 */
	components: {
		PSPDFKitContainer,
	},
	/**
	 * Our component has two methods — one to check when the document is loaded, and the other to open the document.
	 */
	methods: {
		handleLoaded(instance) {
			console.log('PSPDFKit has loaded: ', instance);
			// Do something.
		},

		openDocument(event) {
			// To access the Vue.js instance data properties, use `this` keyword.
			if (this.pdfFile && this.pdfFile.startsWith('blob:')) {
				window.URL.revokeObjectURL(this.pdfFile);
			}
			this.pdfFile = window.URL.createObjectURL(
				event.target.files[0],
			);
		},
	},
};
</script>

<style>
#app {
	font-family: Avenir, Helvetica, Arial, sans-serif;
	text-align: center;
	color: #2c3e50;
}

body {
	margin: 0;
}

input[type='file'] {
	display: none;
}

.custom-file-upload {
	border: 1px solid #ccc;
	border-radius: 4px;
	display: inline-block;
	padding: 6px 12px;
	cursor: pointer;
	background: #4a8fed;
	padding: 10px;
	color: #fff;
	font: inherit;
	font-size: 16px;
	font-weight: bold;
}
</style>

In the code above, there’s a simple template containing three elements inside the #app div: a label, an input, and the PSPDFKitContainer component. The label and input will help you open a local PDF file, and PSPDFKitContainer will assist you in displaying it on the screen.

The input calls the openDocument method as its onChange event handler. This method updates the pdfFile property that triggers a reload of PSPDFKit inside the PSPDFKitContainer as it references this property as the input for the pdfFile prop. You also define a handler for the loaded event emitted by PSPDFKitContainer, but this handler doesn’t do anything right now; you’ll add more logic to it in a little bit.

Using the style tag, you’ll hide the input tag and style the label. This just makes it more visually appealing. You can skip the styles if you want, as they don’t add any functional logic to the application. The image below shows what the label will look like after styling.

Styled input label

In the script tag, import the PSPDFKitContainer component and register it with your app via the components option. Then, define the default value of pdfFile via the data function, and define the handleLoaded and openDocument methods.

Now, if you go back to the browser, you’ll see the demo document loading successfully.

Default PSPDFKit

Try loading a different document via the Open PDF button. It’ll open immediately.

Editing PDF Files Using Vue.js and PSPDFKit

Now that you’ve learned how to open PDFs, this next section will cover some simple editing workflows.

Merging PDFs

PSPDFKit makes it easy to merge two PDF files using the importDocument operation. Go to the App.vue file and add a new data property named mergeFile. This will reference the second PDF that you’ll be merging with the first one. Your data function will look something like this:

data() {
    return {
        pdfFile: this.pdfFile || "/pspdfkit-web-demo.pdf",
        mergeFile: this.mergeFile || "/pspdfkit-web-demo.pdf",
    };
},

You’re using the same demo PDF as the default value for this property, but you can use a different one if you want.

Now, create a mergePDFs method that will do the heavy lifting:

mergePDFs(instance){
    fetch(this.mergeFile)
        .then((res) => {
            if (!res.ok) {
                throw res;
            }
            return res;
        })
        .then((res) => res.blob())
        .then((blob) => {
            instance.applyOperations([
                {
                    type: "importDocument",
                    beforePageIndex: 0,
                    document: blob,
                }
            ]);
        });
}

Next, update the handleLoaded method to resemble this:

handleLoaded(instance) {
    console.log("PSPDFKit has loaded: ", instance);
    this.mergePDFs(instance);
}

When you refresh the page, both PDF files should be merged. The original page count was 5, and the new page count is 10.

Merged PDF

There are multiple options you can tweak while merging the PDFs. Two important ones are importedPageIndexes and beforePageIndex. They allow you to control where the second PDF should be inserted and which pages of the second PDF should be merged with the first one. You can see the available options in the official documentation.

Rotating a Page

PSPDFKit allows you to rotate pages using the rotatePages operation. Create a new rotatePages method and call it from the handleLoaded method:

handleLoaded(instance) {
    console.log("PSPDFKit has loaded: ", instance);
    this.rotatePDF(instance, [0])
}

//...

rotatePages(instance, pageIndexes) {
    instance.applyOperations([
        {
            type: "rotatePages", // Tell PSPDFKit to rotate the page.
            pageIndexes, // Page number(s) to select and rotate.
            rotateBy: 180, // Rotate by 180 degrees. This will flip the page.
        },
    ]);
}

Refresh the browser and the first page of the PDF will now be rotated 180 degrees.

Rotated PDF

Removing Pages

PSPDFKit provides a removePages operation to remove pages from a PDF. Create a new removePages method and call it from the handleLoaded method:

handleLoaded(instance) {
    console.log("PSPDFKit has loaded: ", instance);
    this.removePages(instance, [0])
}

//...

removePages(instance, pageIndexes) {
    instance.applyOperations([
        {
            type: "removePages", // Tell PSPDFKit to remove the page.
            pageIndexes, // Page number(s) to select and remove.
        },
    ]);
},

Refreshing the browser will display the same PDF but with the first page removed.

PDF with a page removed

Adding Pages

PSPDFKit enables adding new pages to a document via the addPage operation. Create an addPage method and call it from the handleLoaded method:

import PSPDFKit from "pspdfkit";

//...

handleLoaded(instance) {
    console.log("PSPDFKit has loaded: ", instance);
    this.addPage(instance)
}

//...

addPage(instance) {
    instance.applyOperations([
        {
            type: "addPage", // Add a page to the document.
            afterPageIndex: instance.totalPageCount - 1, // Append the page at the end.
            backgroundColor: new PSPDFKit.Color({ r: 100, g: 200, b: 255 }), // Set the new page background color.
            pageWidth: 750, // Dimensions of the page:
            pageHeight: 1000,
        },
    ]);
},

You imported PSPDFKit in App.vue because you need to call the Color constructor from the PSPDFKit library. Everything else is similar to what was shown in the other sections. You can modify the color of the new page by tweaking the RGB values passed in to the PSPDFKit.Color method.

If you refresh the browser, you’ll see a brand-new page appended at the end of the PDF file.

New page in PDF

Complete App.vue Code

The complete code for App.vue is included below for reference:

<template>
	<div id="app">
		<label for="file-upload" class="custom-file-upload">
			Open PDF
		</label>
		<input
			id="file-upload"
			type="file"
			@change="openDocument"
			class="btn"
		/>

		<PSPDFKitContainer :pdfFile="pdfFile" @loaded="handleLoaded" />
	</div>
</template>

<script>
import PSPDFKitContainer from '@/components/PSPDFKitContainer';
import PSPDFKit from 'pspdfkit';

export default {
	data() {
		return {
			pdfFile: this.pdfFile || '/pspdfkit-web-demo.pdf',
			mergeFile: this.mergeFile || '/pspdfkit-web-demo.pdf',
		};
	},

	components: {
		PSPDFKitContainer,
	},

	methods: {
		handleLoaded(instance) {
			console.log('PSPDFKit has loaded: ', instance);
			// `this.mergePDFs(instance);`
			// `this.rotatePages(instance, [0]);`
			// `this.removePages(instance, [0]);`
			this.addPage(instance);
		},

		mergePDFs(instance) {
			fetch(this.mergeFile)
				.then((res) => {
					if (!res.ok) {
						throw res;
					}
					return res;
				})
				.then((res) => res.blob())
				.then((blob) => {
					instance.applyOperations([
						{
							type: 'importDocument',
							beforePageIndex: 0,
							document: blob,
						},
					]);
				});
		},

		rotatePages(instance, pageIndexes) {
			instance.applyOperations([
				{
					type: 'rotatePages', // Tell PSPDFKit to rotate the page.
					pageIndexes, // Page number(s) to select and rotate.
					rotateBy: 180, // Rotate by 180 degrees. This will flip the page.
				},
			]);
		},

		removePages(instance, pageIndexes) {
			instance.applyOperations([
				{
					type: 'removePages', // Tell PSPDFKit to remove the page.
					pageIndexes, // Page number(s) to select and remove.
				},
			]);
		},

		addPage(instance) {
			instance.applyOperations([
				{
					type: 'addPage', // Add a page to the document.
					afterPageIndex: instance.totalPageCount - 1, // Append the page at the end.
					backgroundColor: new PSPDFKit.Color({
						r: 100,
						g: 200,
						b: 255,
					}), // Set the new page background color.
					pageWidth: 750, // Dimensions of the page:
					pageHeight: 1000,
				},
			]);
		},

		openDocument(event) {
			if (this.pdfFile && this.pdfFile.startsWith('blob:')) {
				window.URL.revokeObjectURL(this.pdfFile);
			}
			this.pdfFile = window.URL.createObjectURL(
				event.target.files[0],
			);
		},
	},
};
</script>

<style>
#app {
	font-family: Avenir, Helvetica, Arial, sans-serif;
	text-align: center;
	color: #2c3e50;
}

body {
	margin: 0;
}

input[type='file'] {
	display: none;
}

.custom-file-upload {
	border: 1px solid #ccc;
	border-radius: 4px;
	display: inline-block;
	padding: 6px 12px;
	cursor: pointer;
	background: #4a8fed;
	padding: 10px;
	color: #fff;
	font: inherit;
	font-size: 16px;
	font-weight: bold;
}
</style>

Conclusion

This article gives you a glimpse of what’s possible with PSPDFKit’s Vue.js PDF library. It makes it much easier to integrate and work with PDF files in your application. To see a full list of SDK features, you can visit our Vue.js documentation and guides.

If you’d like to test the PSPDFKit for Web SDK, you can request a free trial. Alternatively, you can browse our demo page to see what our API is capable of.

If you encountered any errors while following this tutorial, please refer to our troubleshooting guide. It lists the most common problems and their solutions. Additionally, if you hit any snags, don’t hesitate to reach out to our Support team for help.

We also maintain a GitHub repository with a working Vue.js example project. Please refer to it if you have any issues.

Related Products
Share Post
Free 60-Day Trial Try PSPDFKit in your app today.
Free Trial

Related Articles

Explore more
WEB  |  Web • Vue.js • JavaScript • How to • PDF Generation

Generate a PDF from HTML with Vue.js

TUTORIALS  |  Web • Vue.js • JavaScript • How To • Image Viewer

How to Build a Vue.js Image Viewer with PSPDFKit

TUTORIALS  |  Web • Vue.js • JavaScript • How To • PDF Viewer

How to Build a Vue.js PDF Viewer with PDF.js