> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/get-started/libraries-and-frameworks/vite.md).

# Build a Vite PDF viewer with Apryse WebViewer SDK

Create a Vite-powered PDF viewer and editor with Apryse WebViewer. Learn how to integrate the SDK into your React, Vanilla, Vue, or Svelte apps and render PDFs in the viewer UI.

This guide shows how to build a Vite PDF viewer using the Apryse [WebViewer SDK](/web/what-is-webviewer/overview.md). You’ll learn how to integrate the SDK into React, Vanilla, Vue, or Svelte applications to render, view, and interact with PDF documents in the WebViewer UI.

For more, explore the interactive [Showcase demo](https://showcase.apryse.com/) to see WebViewer's full capabilities in action.

## Prerequisites

This guide assumes basic familiarity with Vite development. Before you start:

* Install [Node.js](https://nodejs.org/en/download) and npm. See the [Vite documentation](https://vite.dev/guide/#scaffolding-your-first-vite-project) for version details.
* Install [Visual Studio Code](https://code.visualstudio.com/Download) or another code editor to develop and debug your code.
* Get your Apryse trial key.

{% @apryse-license-key/apryse-license-key platform="WEB\_VIEWER" variant="full" %}

## 1. Create a Vite project

In this section, you’ll create a new Vite application using npm. This project provides the foundation for integrating Apryse WebViewer. If you already have a React app, skip this and continue to [Install WebViewer](#id-2.-install-webviewer).

1. In your terminal, go to the directory where you want to create the project.
2. Create a new `webviewer-vite` project using a minimal setup:

{% tabs %}
{% tab title="React" %}
{% code lineNumbers="true" %}

```shell
npm create vite@latest webviewer-vite -- --template react
```

{% endcode %}
{% endtab %}

{% tab title="Vanilla" %}
{% code lineNumbers="true" %}

```shell
npm create vite@latest webviewer-vite -- --template vanilla
```

{% endcode %}
{% endtab %}

{% tab title="Vue" %}
{% code lineNumbers="true" %}

```shell
npm create vite@latest webviewer-vite -- --template vue
```

{% endcode %}
{% endtab %}

{% tab title="Svelte" %}
{% code lineNumbers="true" %}

```shell
npm create vite@latest webviewer-vite -- --template svelte
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Info**

Flags are used to skip prompts during project configuration. These flags determine which framework is used and select JavaScript as the variant. Select different options if preferred.
{% endhint %}

3. If prompted to install with npm and start now, select **No**.
4. Navigate to your new Vite project directory and install dependencies:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
cd webviewer-vite
npm install
```

{% endcode %}
{% endtab %}
{% endtabs %}

## 2. Install WebViewer

Next, install the Apryse WebViewer SDK using npm. This command adds the [WebViewer package](https://www.npmjs.com/package/@pdftron/webviewer) to your project, allowing you to integrate the PDF viewer and editor into your Vite application.

After navigating to your `webviewer-vite` project directory, run the following command to install WebViewer:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npm i @pdftron/webviewer
```

{% endcode %}
{% endtab %}
{% endtabs %}

## 3. Copy WebViewer assets

WebViewer needs access to its static assets at runtime, including WebAssembly modules, HTML, and CSS files. In a Vite project, you must copy these assets into the `public` directory so they can be served correctly. We'll use a Vite plugin to copy WebViewer's static assets into the `public` folder. For more, see [Copying WebViewer static assets](/web/get-started/copy-assets.md).

1. From your project directory, run the following to install the [vite-plugin-static-copy](https://www.npmjs.com/package/vite-plugin-static-copy) package:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npm i -D vite-plugin-static-copy
```

{% endcode %}
{% endtab %}
{% endtabs %}

2. In Visual Studio Code, update the `vite.config.js` file to import the `viteStaticCopy` plugin and save. If you don't see a `vite.config.js` file in your project, create one at the project root and add the necessary configuration:

{% tabs %}
{% tab title="React" %}
{% code title="vite.config.js" lineNumbers="true" %}

```js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { viteStaticCopy } from 'vite-plugin-static-copy';

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    react(),
    viteStaticCopy({
      targets: [
        {
          src: 'node_modules/@pdftron/webviewer/public/**/*',
          dest: 'lib/webviewer',
          rename: { stripBase: 4 },
        },
      ],
    }),
  ],
});
```

{% endcode %}
{% endtab %}

{% tab title="Vanilla" %}
{% code title="vite.config.js" lineNumbers="true" %}

```js
import { defineConfig } from 'vite';
import { viteStaticCopy } from 'vite-plugin-static-copy';

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    viteStaticCopy({
      targets: [
        {
          src: 'node_modules/@pdftron/webviewer/public/**/*',
          dest: 'lib/webviewer',
          rename: { stripBase: 4 },
        },
      ],
    }),
  ],
});
```

{% endcode %}
{% endtab %}

{% tab title="Vue" %}
{% code title="vite.config.js" lineNumbers="true" %}

```js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { viteStaticCopy } from 'vite-plugin-static-copy';

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    viteStaticCopy({
      targets: [
        {
          src: 'node_modules/@pdftron/webviewer/public/*/**',
          dest: 'lib/webviewer',
          rename: { stripBase: 4 },
        },
      ],
    }),
  ],
});
```

{% endcode %}
{% endtab %}

{% tab title="Svelte" %}
{% code title="vite.config.js" lineNumbers="true" %}

```js
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { viteStaticCopy } from 'vite-plugin-static-copy';

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    svelte(),
    viteStaticCopy({
      targets: [
        {
          src: 'node_modules/@pdftron/webviewer/public/**/*',
          dest: 'lib/webviewer',
          rename: { stripBase: 4 },
        },
      ],
    }),
  ],
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Info**

Your `vite.config.js` file may look slightly different depending on the framework you’re using. The key requirement is to add the `viteStaticCopy` plugin to the `plugins` array. Make sure to import the plugin correctly:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
import { viteStaticCopy } from 'vite-plugin-static-copy';

```

{% endcode %}
{% endtab %}
{% endtabs %}
{% endhint %}

## 4. Create the PDF viewer

Next, instantiate the Apryse WebViewer SDK and mount it in your Vite project. This involves creating a container for the viewer and initializing WebViewer so it loads correctly at runtime.

{% tabs %}
{% tab title="React" %}

1. In Visual Studio Code, replace the contents of the `src/App.jsx` file with the following and save:

<pre class="language-jsx" data-line-numbers><code class="lang-jsx">import { useEffect, useRef } from 'react';
import WebViewer from '@pdftron/webviewer';

function App() {
  // Create reference to DOM element where WebViewer will mount
  const viewerRef = useRef(null);

  useEffect(() => {
    // Initialize WebViewer once when component mounts
    WebViewer(
      {
        // Path to copied WebViewer static assets
        path: 'lib/webviewer',
        // Replace with your Apryse license key
        licenseKey: '<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>',
        // Initial document to load when WebViewer starts (optional)
        initialDoc: 'https://pdftron.s3.amazonaws.com/downloads/pl/demo-annotated.pdf',
      },
      // Attach WebViewer to container element
      viewerRef.current
    ).then((instance) => {
      // Access WebViewer instance here if needed
      // const { UI, Core } = instance;
    });
  // Empty dependency array ensures this runs only once  
  }, []);
  return (
    // Container element for WebViewer
    &#x3C;div
	    ref={viewerRef}
	    style={{ height: '100vh', width: '100%', margin: '0 auto' }}
	  />
  );
}

export default App;
</code></pre>

{% hint style="info" %}
**Info**

If you're signed in with an Apryse account, your license key is automatically prepopulated in all code snippets.
{% endhint %}

2. Replace the contents of the `src/main.jsx` file with the following and save:

{% code title="src/main.jsx" lineNumbers="true" %}

```jsx
import { StrictMode } from 'react'; 
import { createRoot } from 'react-dom/client';

import App from './App.jsx';

createRoot(document.getElementById('root')).render( 
    <App /> 
);
```

{% endcode %}

{% hint style="info" %}
**Info**

In React 18 and later, `useEffect` may run twice in development when Strict Mode is enabled (which Vite uses by default). This can cause WebViewer to initialize twice and to display a duplicate instance. This behavior is expected and doesn't affect production builds.

For this example, you can avoid duplicate initialization by removing the `StrictMode` wrapper in `src/main.jsx`. However, note that Strict Mode helps identify issues like memory leaks, so removing it isn't recommended for production or more complex applications.
{% endhint %}
{% endtab %}

{% tab title="Vanilla" %}

1. In Visual Studio Code, replace the contents of the `src/main.js` file with the following and save:

<pre class="language-js" data-line-numbers><code class="lang-js">import WebViewer from '@pdftron/webviewer';
import './style.css';

// Initialize WebViewer and mount it to a DOM element
WebViewer(
  {
    // Path to the WebViewer static assets
    path: 'lib/webviewer',
    // Replace with your Apryse license key
    licenseKey: '<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>',
    // Initial document to load when WebViewer starts
    initialDoc: 'https://pdftron.s3.amazonaws.com/downloads/pl/demo-annotated.pdf',
  },
  // The container element where WebViewer will be injected
  document.getElementById('app')
).then((instance) => {
  // This callback runs once WebViewer has fully initialized

  // The 'instance' gives access to:
  // - Core APIs (documentViewer, annotationManager, etc.)
  // - UI customization APIs
  // - Methods for loading documents, handling events, and more

  // Example:
  // const { documentViewer } = instance.Core;
});
</code></pre>

{% hint style="info" %}
**Info**

If you're signed in with an Apryse account, your license key is automatically prepopulated in all code snippets.
{% endhint %}

2. Replace the `src/style.css` with the following and save:

{% code title="src/style.css" lineNumbers="true" %}

```css
.webviewer {
  width: 100%;
  height: 100vh;
  margin: 0 auto;
}
```

{% endcode %}
{% endtab %}

{% tab title="Vue" %}

1. In Visual Studio Code, replace the contents of the `src/components/HelloWorld.vue` file with the following and save:

<pre class="language-vue" data-line-numbers><code class="lang-vue">&#x3C;template>
  &#x3C;!-- Container element where WebViewer will be mounted -->
  &#x3C;div ref="viewer" style="height: 100vh; width: 100%; margin: 0 auto;">&#x3C;/div>
&#x3C;/template>

&#x3C;script setup>
import { ref, onMounted } from 'vue';
import WebViewer from '@pdftron/webviewer';

// Define component props
const props = defineProps({
  initialDoc: String,
});

// Reference to DOM element used as the WebViewer mount point
const viewer = ref(null);

/**
 * Initialize WebViewer once the component is mounted
 * and the DOM element is available
 */
onMounted(() => {
  WebViewer(
    { 
      // Public path where the WebViewer lib assets are served
      path: '/lib/webviewer',
      // Document to load initially (passed in from App.vue)
      initialDoc: props.initialDoc,
      // Replace with your Apryse license key
      licenseKey: '<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>'
    },
    viewer.value,
  );
});
&#x3C;/script>
</code></pre>

{% hint style="info" %}
**Info**

If you're signed in with an Apryse account, your license key is automatically prepopulated in all code snippets.
{% endhint %}

2. Replace the contents of the `src/App.vue` file with the following and save:

{% code title="src/App.vue" lineNumbers="true" %}

```vue
<script setup>
import WebViewer from './components/HelloWorld.vue'
</script>

<template>
  <WebViewer
    initialDoc="https://apryse.s3.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf"
  />
</template>
```

{% endcode %}
{% endtab %}

{% tab title="Svelte" %}

1. In Visual Studio Code, create a `src/lib/WebViewer.svelte` file, add the following code to it, and save:

<pre class="language-svelte" data-line-numbers><code class="lang-svelte">&#x3C;script>
  // @ts-nocheck
  import { onMount } from 'svelte';
  
  // Reference DOM element that will host WebViewer
  let viewer;

  // Run WebViewer setup once component is mounted in DOM
  onMount(() => {
    // Load WebViewer dynamically to avoid build/SSR issues
	  import("@pdftron/webviewer").then(({default: WebViewer}) => {

      // Initialize WebViewer instance
      WebViewer({
        // Path to WebViewer library assets
        path: '/lib/webviewer',
        // Replace with your Apryse license key
        licenseKey: '<code class="expression">visitor.claims.wvKey || "YOUR_LICENSE_KEY"</code>',
        // Initial document to load into viewer
        initialDoc: 'https://apryse.s3.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf',
        }, viewer,
      ).then((instance) => {
	      // WebViewer APIs are available via the instance
	    });
	  });
  });
&#x3C;/script>

&#x3C;style>
#viewer {
  /* Fill viewport with the viewer */
  width: 100%;
  height: 100vh;
  margin: 0 auto;
}
&#x3C;/style>

&#x3C;!-- Container element bound to viewer variable -->
&#x3C;div id="viewer" bind:this={viewer}>&#x3C;/div>
</code></pre>

{% hint style="info" %}
**Info**

If you're signed in with an Apryse account, your license key is automatically prepopulated in all code snippets.
{% endhint %}

2. Replace the contents of the `src/App.svelte` file with the following and save:

{% code title="src/App.svelte" lineNumbers="true" %}

```svelte
<script>
	import WebViewer from './lib/WebViewer.svelte';
</script>

<WebViewer />
```

{% endcode %}
{% endtab %}
{% endtabs %}

## 5. Verify your output

You can now load and display a PDF document in the WebViewer UI. Run your React application to launch WebViewer and see the PDF in your browser.

1. From your project directory, run the following command to start the application:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
npm run dev
```

{% endcode %}
{% endtab %}
{% endtabs %}

A successful output looks similar to:

{% tabs %}
{% tab title="Shell" %}
{% code lineNumbers="true" %}

```shell
> webviewer-vite@0.0.0 dev
> vite


  VITE v8.0.16  ready in 920 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help
[vite-plugin-static-copy] Collected 817 items.
```

{% endcode %}
{% endtab %}
{% endtabs %}

2. Open the localhost URL from your terminal to view the WebViewer UI and PDF document.

{% hint style="info" %}
**Clean up CSS**

If you created your project using Vite’s scaffolding tool, the default CSS files included with the template can interfere with WebViewer’s layout. If the viewer doesn't appear or renders incorrectly, remove or clear the styles from any default CSS files (such as `style.css` or `index.css`).
{% endhint %}

***

### Get started video

In this 4-minute video, learn the fundamentals of Apryse WebViewer, including key concepts for installation and initialization in any web application.

{% embed url="<https://www.youtube.com/embed/UIIWdERmBtU?si=ZIOH-IIi9PqhqEDv>" %}
Overview of Apryse WebViewer fundamentals, including installation and initialization.
{% endembed %}

## Next steps

<a href="/web/what-is-webviewer/usage.md" class="button primary">Usage</a><a href="/web/get-started/guides.md" class="button primary">Guides</a><a href="/web/get-started/samples.md" class="button primary">Samples</a><a href="https://sdk.apryse.com/api/web/index.html" class="button primary">API docs</a>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/get-started/libraries-and-frameworks/vite.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
