Blog Post

How to Upload an Image and Insert It as an Annotation with Vue.js

Illustration: How to Upload an Image and Insert It as an Annotation with Vue.js

In this post, we’ll show you how to set up a UI to add an image to the top-left corner of a PDF document as an annotation.

More specifically, we’ll create the “Add logo” button in the PSPDFKit toolbar, and every time the button is clicked, it’ll add an image annotation to a PDF — and all of this from within your Vue.js app!

We’ll assume you already know how to load PSPDFKit inside your app. If that’s not the case, please refer to our Open and Annotate PDFs from Your Vue.js App blog post.

Loading PSPDFKit

Let’s start by loading PSPDFKit with Vue.js:

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8" />
    <title>PSPDFKit for Web example - Vue</title>
    <!-- Vue library loaded here -->
    <script src=""></script>
    <!-- PSPDFKit for Web library loaded here -->
    <script type="text/javascript" src="pspdfkit.js"></script>
      /* Basic layout styling to be able to show the UI */
      body {
        height: 100vh;

      .container {
        height: 100%;
    <!-- Template for the main app component -->
    <div id="app">
        <input type="file" id="selectDocument" v-on:change="openDocument" />
        <span class="error">{{errorMsg}}</span>
      <div class="App-viewer">
          @update:error="errorMsg = $event"
       * Change the 'YOUR_LICENSE_KEY_GOES_HERE' string to your actual license key from PSPDFKit.
       * PSPDFKit for Web example component.
      const pspdfkit = Vue.component("pspdfkit", {
         * PSPDFKit for Web UI container template.
        template: '<div class="container"></div>',
        name: "pspdfkit",
         * The component receives these parameters:
         * `@documentUrl: string` — URL of the document to be loaded.
         * `@licenseKey: string` — license key (from the variable set above).
         * `@baseUrl: string` — URL from which the PSPDFKit library should get its payload and artifacts.
        props: ["documentUrl", "licenseKey", "baseUrl"],
        _instance: null,
         * We wait until the template has been rendered to load the document into the library.
        mounted: function mounted() {
         * Our component has two methods: one to trigger document loading, and the other to unload and clean up
         * so that the component is ready to load another document.
        methods: {
          load: function load() {
              document: this.documentUrl,
              container: ".container",
              licenseKey: this.licenseKey,
              baseUrl: this.baseUrl
              .then(instance => {
                this._instance = instance;
                this.$emit("update:error", "");
              .catch(err => {
                this.$emit("update:error", err.message);
          unload: function unload() {
            if (this._instance) {
              PSPDFKit.unload(this._instance || ".container");
              this._instance = null;
         * We watch for `documentUrl` prop changes and trigger unloading and loading when there's a new document to load.
        watch: {
          documentUrl: function documentUrl() {
         * Clean up when the component is unmounted (not needed in this example).
        beforeDestroy: function beforeDestroy() {

       * Container component, which includes a button to open a PDF file and the URL of the example PDF loaded
       * by default. Its template is inlined in the HTML above.
      new Vue({
        components: { pspdfkit },
        el: "#app",
        name: "pspdfkit-web-example-vue",
        data: function data() {
          return {
            documentUrl: this.documentUrl || "example.pdf",
            baseUrl: "",
            errorMsg: ""
        methods: {
          openDocument: function openDocument(event) {
            if (this.documentUrl) {
            this.documentUrl = window.URL.createObjectURL(

Adding the Button

Now let’s tweak the toolbar to only contain one button, our Add logo button. To do this in the load function, we’ll need to add the following:

toolbarItems: [
    type: "custom",
    title: "Add logo",
    className: "addLogo",
    name: "addLogo",

Assigning the Behavior

The next step is adding the behavior to our button. Every time it’s clicked, the button will add our logo, an image annotation, to the top-left corner of the loaded PDF:

onPress: async () => {
  // Get the image.
  const request = await fetch("/pspdfkit.png");
  const blob = await request.blob();
  const imageAttachmentId = await this._instance.createAttachment(
    new PSPDFKit.Annotations.ImageAnnotation({
      pageIndex: 0,
      contentType: "image/png",
      description: "Logo Image Annotation",
      boundingBox: new PSPDFKit.Geometry.Rect({
        left: 10,
        top: 10,
        width: 150,
        height: 150,

In general, the preferred way is to import an image in the JavaScript module, but to keep this example simple, we won’t use webpack. Instead, we’ll fetch the image from the public folder (see Vue CLI).

And that’s it! Now our page looks like the following.

PDF without Logo

Clicking the Add logo button will add the logo image annotation.

PDF with logo


It was surprisingly simple to add a logo to our PDF. As this example demonstrates, we can simplify opening and annotating PDF documents by making use of PSPDFKit for Web, an opinionated PDF SDK that can be used with (and without) any JavaScript framework. It supports all modern mobile and desktop browsers and multiple languages.

We encourage you to check out all the features included in PSPDFKit.

Thank you for following this example and reading our blog.

Related Products
Share Post

Related Articles

Explore more
RELEASES  |  Web • Products

PSPDFKit for Web 2021.1: Collaboration Permissions

RELEASES  |  Web • Products

PSPDFKit for Web Adds Annotation Notes and Improves Accessibility

RELEASES  |  Web • Products

PSPDFKit for Web Introduces New CRUD API