---
title: "How to build a Vue.js PDF viewer"
canonical_url: "https://www.nutrient.io/blog/how-to-build-a-vuejs-pdf-viewer/"
md_url: "https://www.nutrient.io/blog/how-to-build-a-vuejs-pdf-viewer.md"
last_updated: "2026-07-10T06:08:04.774Z"
description: "Learn how to build a Vue.js PDF viewer with Nutrient. This tutorial covers Vue CLI setup, SDK integration, and adding annotation, signing, and editing features."
---

**TL;DR**

This step-by-step tutorial demonstrates how to build a [Vue.js PDF viewer](https://www.nutrient.io/sdk/web/getting-started/other-frameworks/) using Nutrient. It covers project setup, Vue CLI installation, PDF library integration, and component creation for displaying and interacting with PDF documents. The guide showcases Nutrient’s Vue.js PDF viewer library with 30+ features, including annotation tools, document editing, signing capabilities, and support for multiple file types, like PDF, MS Office, and images.

This post provides you with a step-by-step guide on how you can deploy Nutrient’s Vue.js PDF viewer. [Vue.js](https://vuejs.org/) is a popular frontend JavaScript framework for building single-page applications (SPAs) and user interfaces (UIs), and it’s one of the most starred projects on [GitHub](https://github.com/vuejs/vue). It enables users to create rapid prototypes and build fast and reliable applications.

## What is a Vue.js PDF viewer?

A Vue.js [PDF viewer](https://www.nutrient.io/sdk/solutions/viewing/) lets you render and view PDF documents in a web browser without the need to download it to your hard drive or use an external application like a PDF reader.

## Nutrient Vue.js PDF viewer

We offer a commercial [Vue.js PDF viewer library](https://www.nutrient.io/guides/web/viewer.md) that can easily be integrated into your web application. It comes with 30+ features that let you view, annotate, edit, and sign documents directly in your browser. Out of the box, it has a polished and flexible UI that you can extend or simplify based on your unique use case.

- A prebuilt and polished UI for an improved user experience

- 15+ prebuilt annotation tools to enable document collaboration

- Support for more file types with client-side [PDF](https://www.nutrient.io/guides/web.md), [MS Office](https://www.nutrient.io/guides/web/viewer.md), and [image](https://www.nutrient.io/guides/web/viewer/images.md) viewing

- Dedicated support from engineers to speed up integration

## Example of our Vue.js PDF viewer

To demo our [Vue.js PDF viewer](https://www.nutrient.io/demo/), upload a PDF, JPG, PNG, or TIFF file by clicking Open Document under the Standalone option (if you don’t see this option, select Choose Example from the dropdown). Once your document is displayed in the viewer, try drawing freehand, adding a note, or applying a crop or an eSignature.

## Requirements to get started

To get started, you’ll need:

- [Git](https://git-scm.com/downloads)

- [Node.js](https://nodejs.org/en/) (version 18 or later recommended)

- A package manager for installing the Vue command-line interface (CLI) and importing packages — you can use [npm](https://www.npmjs.com/) or [Yarn](https://yarnpkg.com/)

## Installing the Vue CLI

To work with Vue.js, you need to install [Vue CLI](https://cli.vuejs.org/), which is standard tooling for Vue.js. It helps you create, build, and run Vue.js applications.

You can install the CLI using [`npm`](https://www.npmjs.com/get-npm), which comes with Node.js, or [`yarn`](https://yarnpkg.com/lang/en/docs/install/):

```bash

npm install -g @vue/cli

```

```bash

yarn global add @vue/cli

```

You can check the version of Vue by running the following:

```bash

vue --version

```

This tutorial uses Vue CLI version 5 or later. Note that Vue CLI is now in maintenance mode — for new projects, the Vue team recommends [create-vue](https://github.com/vuejs/create-vue) (Vite-based). The Nutrient integration below works the same either way.

## Creating the project

Now you’ll learn how to integrate Nutrient into your Vue.js project.

1. Vue CLI provides an easy way of creating projects by using the following command:

```bash

vue create pspdfkit-vue-project

```

Here, you’re using the `create` option with the name of the project you want to create (`pspdfkit-vue-project`).

It’ll then ask some configuration questions.

2. Select Default (Vue 3) (`[Vue 3] babel, eslint`) from the list.![screen showing the vue.js project creation](@/assets/images/blog/2021/how-to-build-a-vuejs-pdf-viewer-with-pdfjs/vue-cli-project-creation.png)

3. Now, change the directory to `pspdfkit-vue-project`:

```bash

cd pspdfkit-vue-project

```

### Adding Nutrient

1. Install `@nutrient-sdk/viewer` as a dependency with `npm` or `yarn`:

```bash

npm install @nutrient-sdk/viewer

```

```bash

yarn add @nutrient-sdk/viewer

```

2. Now you can start building your Vue.js project. First, create a `js` directory under the `public` directory. Go to your terminal and run:

```bash

mkdir -p public/js

```

3. Copy the Nutrient Web SDK library assets to the `public/js` directory:

```shell

cp -R./node_modules/@nutrient-sdk/viewer/dist/nutrient-viewer-lib public/js/nutrient-viewer-lib

```

This will copy the `nutrient-viewer-lib` directory from within `node_modules/` into the `public/js/` directory to make it available to the SDK at runtime.

### Displaying the PDF

1. Add the PDF document you want to display to the `public` directory. You can use our [demo document](https://www.nutrient.io/example.pdf) as an example.

2. Add a component wrapper for the Nutrient library and save it as `src/components/NutrientContainer.vue`:

```vue

// src/components/NutrientContainer.vue

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

<script>
import NutrientViewer from "@nutrient-sdk/viewer";

export default {
  name: "NutrientContainer",
  /**
   * The component receives the `pdfFile` 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.loadNutrient().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.loadNutrient();
      }
    },
  },
  /**
   * Our component has the `loadNutrient` method. This unloads and cleans up the component and triggers document loading.
   */
  methods: {
    async loadNutrient() {
      NutrientViewer.unload(".pdf-container");
      return NutrientViewer.load({
        // To access the `pdfFile` from props, use `this` keyword.
        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() {
    NutrientViewer.unload(".pdf-container");
  },
};
</script>

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

```

Here’s what’s happening in the component:

- The `template` section is rendering a `div` with the `pdf-container` class. This will help you declaratively bind the rendered DOM to the underlying component instance’s data.

- The `script` section is defining a Vue.js instance named `NutrientContainer` and creating methods for mounting, loading, and unloading PDF files into the `pdf-container`.

- The `style` section is defining the height of the container.

3. Now, replace the contents of `src/App.vue` with the following:

```vue

// src/App.vue

<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" />
    <NutrientContainer :pdfFile="pdfFile" @loaded="handleLoaded" />
  </div>
</template>

<script>
import NutrientContainer from "@/components/NutrientContainer.vue";

export default {
  data() {
    return {
      pdfFile: "/example.pdf",
    };
  },
  /**
   * Render the `NutrientContainer` component.
   */
  components: {
    NutrientContainer,
  },
  /**
   * 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("Nutrient has loaded: ", instance);
      // Do something.
    },

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

<style>
#app {

  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 `template` section, you have a file upload input and the `NutrientContainer` component.

Vue.js uses directives to handle some types of functionality. For the input field, you’re using the `v-on` directive to attach an event listener to the element. In this case, it’s the `change` event. There’s a shortcut to `v-on` that removes the keyword and uses an `@` symbol instead.

```js

v-on:change="openDocument"
v-on:loaded="handleLoaded"
// Or
@change="openDocument"
@loaded="handleLoaded"

```

Similar to the input field, for the `NutrientContainer` component, you’re using the `v-bind` directive to bind the `pdfFile` property to the `pdfFile` property of the component and attaching an event listener for the `loaded` event:

```js

<NutrientContainer :pdfFile="pdfFile" @loaded="handleLoaded" />

```

- In the `script` section, you can see the implementation of the `handleLoaded` and `openDocument` methods. Also, there’s a data function that returns the `pdfFile` property.

The data keeps track of reactive state within the current component. It’s always a function and returns an object. The object’s top-level properties are exposed via the component instance.

- In the `style` section, there are styles for custom file input, and there are some general styles for the `app`.

4. Start the app:

```bash

npm run serve

```

```bash

yarn serve

```

You can see the application running on `localhost:8080`.

If you can’t see your PDF file rendered in the browser, make sure you actually uploaded a PDF file inside the `public` directory.

In the demo application, you can open different PDF files by clicking the Open PDF button. You can add signatures, annotations, stamps, and more.

The finished code is available on [GitHub](https://github.com/PSPDFKit/nutrient-web-examples/tree/main/examples/vue). You can find the example code for Vue 2 in the `vue-2` branch.

## Adding even more capabilities

Once you’ve deployed your viewer, you can start customizing it to meet your specific requirements or easily add more capabilities. To help you [get started](https://www.nutrient.io/sdk/web/getting-started/other-frameworks/), here are some of our most popular Vue.js guides:

- [Adding annotations](https://www.nutrient.io/guides/web/annotations.md)

- [Editing documents](https://www.nutrient.io/guides/web/editor.md)

- [Filling PDF forms](https://www.nutrient.io/guides/web/forms.md)

- [Adding signatures to documents](https://www.nutrient.io/guides/web/signatures.md)

- [Real-time collaboration](https://www.nutrient.io/guides/web/instant-synchronization.md)

- [Redaction](https://www.nutrient.io/guides/web/redaction.md)

- [UI customization](https://www.nutrient.io/guides/web/user-interface.md)

## Conclusion

You should now have our Vue.js PDF viewer up and running in your web application. If you hit any snags, don’t hesitate to reach out to our [Support team](https://www.nutrient.io/support/request) for help.

You can also integrate our PDF viewer using web frameworks like [Angular](https://www.nutrient.io/blog/how-to-build-an-angular-pdf-viewer/), [jQuery](https://www.nutrient.io/blog/how-to-build-a-jquery-pdf-viewer/), and [React.js](https://www.nutrient.io/blog/how-to-build-a-reactjs-pdf-viewer.md). To see a list of all web frameworks, start your [free trial](https://www.nutrient.io/try/). Or, [launch our demo](https://www.nutrient.io/demo/) to see our viewer in action.

Do you prefer an open source approach in Vue? See how to build a [Vue.js PDF viewer with PDF.js](https://www.nutrient.io/blog/how-to-build-a-vuejs-pdf-viewer-with-pdfjs.md).

## FAQ

#### What is a Vue.js PDF viewer?

A Vue.js PDF viewer renders PDF documents directly in a web browser without downloading them or using an external PDF reader application. It integrates with Vue.js components for seamless document viewing.

#### How do I integrate Nutrient into a Vue.js project?

Install `@nutrient-sdk/viewer` via npm or yarn, copy the SDK assets to your `public/js` directory, create a wrapper component that calls `NutrientViewer.load()`, and use the component in your Vue application.

#### What features does Nutrient offer for Vue.js PDF viewing?

Nutrient includes 30+ features: annotation tools (highlights, comments, ink), document editing, form filling, digital signatures, and support for PDF, MS Office, and image files.

#### Can I open different PDF files dynamically?

Yes. The component watches for prop changes and automatically reloads when a new document is provided. Use `window.URL.createObjectURL()` to create a URL from a file input selection.

#### Does Nutrient work with Vue 2 and Vue 3?

Yes. Nutrient supports both Vue 2 and Vue 3. The example code for Vue 2 is available in the `vue-2` branch of the GitHub repository.
---

## Related pages

- [Accessibility Untangled Why It Matters Guide](/blog/accessibility-untangled-why-it-matters-guide.md)
- [The business case for accessibility: Five ways it drives enterprise value](/blog/5-ways-accessibility-drives-enterprise-value.md)
- [Advanced Techniques For React Native Ui Components](/blog/advanced-techniques-for-react-native-ui-components.md)
- [Angular File Viewer Pdf Image Office Files](/blog/angular-file-viewer-pdf-image-office-files.md)
- [Ai Document Automation Extraction To Action](/blog/ai-document-automation-extraction-to-action.md)
- [Auto Tagging And Document Accessibility In Dotnet Sdk](/blog/auto-tagging-and-document-accessibility-in-dotnet-sdk.md)
- [Ai Legal Assistant Document Authoring](/blog/ai-legal-assistant-document-authoring.md)
- [The CEO’s AI playbook: Why decision architecture beats model selection](/blog/ceo-ai-playbook-decision-architecture.md)
- [Best Document Viewers](/blog/best-document-viewers.md)
- [Convert One Drive Files To Pdf In Sharepoint](/blog/convert-one-drive-files-to-pdf-in-sharepoint.md)
- [Complete Guide To Pdfjs](/blog/complete-guide-to-pdfjs.md)
- [Construction Document Data Extraction](/blog/construction-document-data-extraction.md)
- [Create And Edit Pdfs In Flutter](/blog/create-and-edit-pdfs-in-flutter.md)
- [Create Pdfs With React](/blog/create-pdfs-with-react.md)
- [Creating A Document Scanner With Ocr In Python](/blog/creating-a-document-scanner-with-ocr-in-python.md)
- [The CTO’s AI playbook: Why accountability architecture beats orchestration](/blog/cto-ai-playbook-accountability-architecture.md)
- [Digital Workflow Automation](/blog/digital-workflow-automation.md)
- [Digital Signatures](/blog/digital-signatures.md)
- [Document Ai Vs Ocr](/blog/document-ai-vs-ocr.md)
- [Document Viewer](/blog/document-viewer.md)
- [app.py](/blog/extract-text-from-pdf-using-python.md)
- [How To Build A Dotnet Maui Pdf Viewer](/blog/how-to-build-a-dotnet-maui-pdf-viewer.md)
- [Emerging threats: Your logging system may be an agentic threat vector](/blog/emerging-threats-your-logging-system.md)
- [How To Build A Flutter Pdf Viewer](/blog/how-to-build-a-flutter-pdf-viewer.md)
- [How To Build A Javascript Pdf Viewer](/blog/how-to-build-a-javascript-pdf-viewer.md)
- [or](/blog/how-to-build-a-javascript-pdf-viewer-with-pdfjs.md)
- [How To Build A React Powerpoint Viewer](/blog/how-to-build-a-react-powerpoint-viewer.md)
- [or](/blog/how-to-build-a-nextjs-pdf-viewer.md)
- [How To Build A Powerpoint Viewer Using Javascript](/blog/how-to-build-a-powerpoint-viewer-using-javascript.md)
- [How To Build A React Native Pdf Viewer](/blog/how-to-build-a-react-native-pdf-viewer.md)
- [How To Build A Reactjs File Viewer](/blog/how-to-build-a-reactjs-file-viewer.md)
- [Using Yarn](/blog/how-to-build-a-react-excel-viewer.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer-with-react-pdf.md)
- [How To Build A Vuejs Pdf Viewer With Pdfjs](/blog/how-to-build-a-vuejs-pdf-viewer-with-pdfjs.md)
- [How To Build A Reactjs Viewer With Pdfjs](/blog/how-to-build-a-reactjs-viewer-with-pdfjs.md)
- [How To Build An Angular Pdf Viewer With Pdfjs](/blog/how-to-build-an-angular-pdf-viewer-with-pdfjs.md)
- [How To Build An Angular Pdf Viewer With Ng2 Pdf Viewer](/blog/how-to-build-an-angular-pdf-viewer-with-ng2-pdf-viewer.md)
- [How To Convert Html To Pdf Using Html2pdf](/blog/how-to-convert-html-to-pdf-using-html2pdf.md)
- [How To Build An Android Pdf Viewer](/blog/how-to-build-an-android-pdf-viewer.md)
- [or](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-python.md)
- [or](/blog/how-to-convert-html-to-pdf-using-react.md)
- [How To Convert Word To Pdf In Nodejs](/blog/how-to-convert-word-to-pdf-in-nodejs.md)
- [How To Create Pdfs With React To Pdf](/blog/how-to-create-pdfs-with-react-to-pdf.md)
- [How To Edit Pdfs Using Ios Pdf Library](/blog/how-to-edit-pdfs-using-ios-pdf-library.md)
- [How To Embed A Pdf Viewer In Your Website](/blog/how-to-embed-a-pdf-viewer-in-your-website.md)
- [base_url tells WeasyPrint where to resolve relative asset paths](/blog/how-to-generate-pdf-reports-from-html-in-python.md)
- [How To Generate Pdf From Html With Nodejs](/blog/how-to-generate-pdf-from-html-with-nodejs.md)
- [From an HTML string.](/blog/html-in-pdf-format.md)
- [Swift Package Manager](/blog/mobile-pdf-sdk.md)
- [Open an image.](/blog/how-to-use-tesseract-ocr-in-python.md)
- [Linearized Pdf](/blog/linearized-pdf.md)
- [`elements` come from your document parser — each has a type and content.](/blog/multimodal-rag.md)
- [Nutrient Vs Conga Composer](/blog/nutrient-vs-conga-composer.md)
- [Open Pdf In Your Web App](/blog/open-pdf-in-your-web-app.md)
- [Pdf Page Labels](/blog/pdf-page-labels.md)
- [Online Document Viewer](/blog/online-document-viewer.md)
- [Pdf Sdk Performance Benchmark](/blog/pdf-sdk-performance-benchmark.md)
- [Pdfjs Annotation Editor Layer](/blog/pdfjs-annotation-editor-layer.md)
- [Pdf Ua Compliance Guide](/blog/pdf-ua-compliance-guide.md)
- [Pdf Sdk Compliance Security Checklist](/blog/pdf-sdk-compliance-security-checklist.md)
- [Pdfjs Area Annotations Canvas Capture](/blog/pdfjs-area-annotations-canvas-capture.md)
- [Pdfjs Coordinate Systems Pdf To Screen](/blog/pdfjs-coordinate-systems-pdf-to-screen.md)
- [Pdfjs Eventbus Guide](/blog/pdfjs-eventbus-guide.md)
- [Pdfjs Navigation Zoom Rotation](/blog/pdfjs-navigation-zoom-rotation.md)
- [Pdfjs Native Annotation Layer Forms](/blog/pdfjs-native-annotation-layer-forms.md)
- [Pdfjs Pdf Page Manipulation Pdf Lib](/blog/pdfjs-pdf-page-manipulation-pdf-lib.md)
- [Pdfjs Limitations Commercial Upgrade](/blog/pdfjs-limitations-commercial-upgrade.md)
- [Pdfjs Sticky Note Annotations](/blog/pdfjs-sticky-note-annotations.md)
- [Pdfjs React Viewer Setup](/blog/pdfjs-react-viewer-setup.md)
- [Pdfjs Server Side Text Extraction](/blog/pdfjs-server-side-text-extraction.md)
- [Pdfjs Rendering Overlays React Portals](/blog/pdfjs-rendering-overlays-react-portals.md)
- [Pdfjs Thumbnail Sidebar](/blog/pdfjs-thumbnail-sidebar.md)
- [Pdfjs Text Highlight Annotations](/blog/pdfjs-text-highlight-annotations.md)
- [Pdfjs Text Search Pdffindcontroller](/blog/pdfjs-text-search-pdffindcontroller.md)
- [Process Flows](/blog/process-flows.md)
- [or](/blog/sample-blog-updated.md)
- [React Native Pdf Annotation](/blog/react-native-pdf-annotation.md)
- [Open an image file.](/blog/tesseract-python-guide.md)
- [Convert an HTML file to PDF.](/blog/top-ten-ways-to-convert-html-to-pdf.md)
- [Vector Pdf](/blog/vector-pdf.md)
- [Top 5 Javascript Pdf Viewers](/blog/top-5-javascript-pdf-viewers.md)
- [Web Sdk Is Now Headless](/blog/web-sdk-is-now-headless.md)
- [Wcag2 Accessibility Requirements Documents](/blog/wcag2-accessibility-requirements-documents.md)
- [What Is A Vpat](/blog/what-is-a-vpat.md)
- [What Are Annotations](/blog/what-are-annotations.md)
- [Why Your Ai Agent Hallucinates Pdf Table Data](/blog/why-your-ai-agent-hallucinates-pdf-table-data.md)
- [What Is Pdf Ua](/blog/what-is-pdf-ua.md)
- [Why Pdfium Is A Trusted Platform For Pdf Rendering](/blog/why-pdfium-is-a-trusted-platform-for-pdf-rendering.md)

