---
title: "Setup — Vue"
description: "Install the viewer, give it a size, pass it config, render on the server, and run several viewers on one page."
integration: "Vue"
source: "https://www.cloudpdf.com/docs/viewer/vue/setup"
---

# Setup

One package gives you the whole viewer: the toolbar and panels, and the engine that opens your
documents on CloudPDF.

**`install.sh`**

```shellscript
npm install @cloudpdf/viewer-vue@next
```

On a plain HTML page, load the script from jsDelivr as above. In an app with a bundler, install
`@cloudpdf/viewer` and `import '@cloudpdf/viewer'` once, which defines the `<embedpdf-viewer>`
element.

## Give it a size

The viewer fills the box you give it and scrolls the pages inside it, so the box needs a height.
Any height works: a fixed one, `100vh`, or the remaining space of a flex or grid layout
(`flex: 1; min-height: 0`). Its width follows the box too, and the viewer adapts to it, not to the
window: see [Small screens](customize/small-screens).

## Pass it config

Everything the viewer can do is one config object. In a framework, every key is a prop:

**`config.vue`**

```vue
<script setup lang="ts">
import { PDFViewer, type Viewer } from '@cloudpdf/viewer-vue';

const disable = ['forms'];
const onReady = (viewer: Viewer) => console.log('ready', viewer);
</script>

<template>
  <PDFViewer
    :src="{ grant: 'shr_gvpJcG1ULUMon19C0D1wODSY' }"
    theme="system"
    :disable="disable"
    style="height: 100vh"
    @ready="onReady"
  />
</template>
```

| Key                | What it is                                                                                                                  | Page                                                             |
| :----------------- | :-------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------- |
| `src`              | One document: `{ token }`, `{ id }` or `{ grant }`                                                                          | [Documents](documents)                                           |
| `documents`        | Several documents, shown as tabs                                                                                            | [Documents](documents#several-documents)                         |
| `layout`           | Where every toolbar, button, menu and panel goes                                                                            | [Layout](customize/layout)                                       |
| `size`             | `'auto'` (default), or the layout of one size at every width: `'compact'`, `'medium'` or `'expanded'`                       | [Small screens](customize/small-screens#one-size-at-every-width) |
| `touch`            | `'auto'` (default), or `true` or `false`: a finger's 44 px buttons on any pointer, or on none                               | [Small screens](customize/small-screens#touch)                   |
| `commands`         | Your own actions                                                                                                            | [Buttons & commands](customize/commands)                         |
| `appState`         | Your app's state, which your commands read                                                                                  | [Buttons & commands](customize/commands#your-apps-state)         |
| `icons`            | Your own icons                                                                                                              | [Buttons & commands](customize/commands#icons)                   |
| `theme`            | `'light'`, `'dark'`, `'system'`, or your colors                                                                             | [Theming](customize/theming)                                     |
| `locale`           | `'auto'` or a language code                                                                                                 | [Translations](customize/translations)                           |
| `strings`          | Your own words, and other languages                                                                                         | [Translations](customize/translations)                           |
| `disable`          | Features, or single buttons, to leave out                                                                                   | [Turn features off](features/turning-off)                        |
| `readOnly`         | Every feature that changes the document off                                                                                 | [Turn features off](features/turning-off#read-only)              |
| `notAllowed`       | `'hide'` (default) or `'disable'` what the user's token doesn't allow                                                       | [Turn features off](features/turning-off#what-a-user-may-do)     |
| `plugins`          | The settings of each feature's plugin                                                                                       | [Plugins](code/plugins#settings)                                 |
| `fonts`            | Ignored on the cloud: your server's fonts are the ones offered                                                              | [Fonts](features/fonts)                                          |
| `engine`           | Your own CloudPDF server (`baseUrl`), the engine's own `token`, or another engine                                           | [Self-hosting](self-hosting)                                     |
| `onReady`          | Called with the `viewer` once it's live                                                                                     | [The viewer in code](code/viewer)                                |
| `onDocumentChange` | Called with the document that's showing: the first one, each one the user switches to, and `null` after the last one closes | [Documents](documents#several-documents)                         |
| `onPanelResize`    | Called with a panel's id and width when the user resizes it                                                                 | [Panels](customize/panels#keep-the-width-people-chose)           |

Who the user is and what they may do come from the document's token, so there's no `scope` or
`identity`.

The config is plain data and a few functions, the same in every framework. Keep it in a file of its
own when it grows, and spread it into the viewer, as in the [Quick start](quick-start#3-make-it-yours).

## TypeScript

Every key is typed, including the ids of the built-in buttons and panels, so your editor completes
them. A config in a file of its own gets its types from `satisfies`:

```ts
import type { ViewerConfig } from '@cloudpdf/viewer';

export const config = {
  theme: { accent: '#7c3aed' },
  layout: (layout) => layout.place('main', 'bottom'),
} satisfies ViewerConfig;
```

Every framework package exports the same `ViewerConfig` type.

## Server-side rendering

The viewer runs in the browser only, and every framework package is safe to import on the server.
The server renders an empty box of the size you gave it, and the viewer starts when the page loads
in the browser, so there's nothing to wrap:

**`ssr.vue`**

```vue
<!-- pages/report.vue in Nuxt: no <ClientOnly> needed. -->
<script setup lang="ts">
import { PDFViewer } from '@cloudpdf/viewer-vue';
</script>

<template>
  <PDFViewer :src="{ grant: 'shr_gvpJcG1ULUMon19C0D1wODSY' }" style="height: 100vh" />
</template>
```

Next.js, Nuxt, SvelteKit, Astro and Angular SSR all work this way. With Angular, `@defer (on
viewport)` also keeps the viewer's code out of the first download until it scrolls into view.

## Open a CloudPDF document

Each document opens with a token your backend creates for the user. It says who they are and what
they may do:

```js
{
  src: { token: await fetchDocumentToken('contract-42') },
}
```

Pass a function to get a fresh token when an old one runs out:
`src: { token: () => fetchDocumentToken('contract-42') }`. See
[Authentication](https://www.cloudpdf.com/docs/engine/authentication) for the ways to open a document and what a token
carries.

## Change the config later

Six keys follow their prop while the viewer runs: `src` opens the new document in place of the
old one; `theme` and `locale` switch the look and the language; `disable` and `readOnly` take tools
away or bring them back; `appState` gives [your commands](customize/commands#your-apps-state) your
app's state as it is now.

Any plugin's settings change through the `viewer` (see [Plugins](code/plugins#settings)).
Everything else is read once, when the viewer starts. To change it, mount a new viewer:

**`remount.vue`**

```vue
<script setup lang="ts">
import { PDFViewer, type Layout } from '@cloudpdf/viewer-vue';

defineProps<{ toolbarBelow: boolean }>();

const toolbarAtBottom = (layout: Layout) => layout.place('main', 'bottom');
</script>

<template>
  <!-- A new key mounts a new viewer with the new config. -->
  <PDFViewer
    :key="toolbarBelow ? 'below' : 'above'"
    :src="{ grant: 'shr_gvpJcG1ULUMon19C0D1wODSY' }"
    :layout="toolbarBelow ? toolbarAtBottom : undefined"
    style="height: 100vh"
  />
</template>
```

A new viewer opens its documents again.

## Several viewers on a page

Each viewer has its own documents, layout, settings and state. Keyboard shortcuts work in the
viewer that has focus, so two viewers never both zoom on one key press.

## Good to know

### What it needs from the browser

Chrome and Edge 114, Firefox 125 and Safari 17 (iOS 17), or newer: the first versions with the
popover API, which the viewer's menus and dialogs open in.

The pages render on CloudPDF. Stamps and Signatures open their libraries in the browser, in a Web
Worker, as WebAssembly.

### A strict Content Security Policy

The viewer runs under a strict CSP with no `'unsafe-inline'`. [Security & CSP](concepts/security)
has the policy to copy.

### Air-gapped and self-hosted

The viewer talks to one server: CloudPDF SaaS, or your own CloudPDF when `engine: { baseUrl }`
names it. See [Self-hosting](self-hosting) for running your own and the files the browser loads.

> The viewer is built on the same packages as [headless](https://www.cloudpdf.com/docs/headless/vue). Everything you set up here
> still applies if you build your own interface later.
