usePDF
The usePDF composable owns a pdf() instance and exposes reactive render state for previewing in the browser. It is the Vue analog of react-pdf's usePDF hook and returns a [state, update] tuple.
Signature
function usePDF(options?: {
document?: DocumentTree
}): [Ref<PDFState>, (document: DocumentTree) => void]Options
| Prop | Type | Default | Description |
|---|---|---|---|
document | DocumentTree | — | Optional initial document tree. Rendering starts immediately when provided; omit it and call the updater instead. |
Return Value
A two-element tuple. The first element is a Ref holding the render state — read it as instance.value.url in script, or instance.url in a template. The second is an updater that swaps in a new document tree.
const [instance, update] = usePDF()State (instance.value)
| Prop | Type | Default | Description |
|---|---|---|---|
url | string | null | null | Blob URL for preview. Revoked automatically when replaced or on unmount. |
blob | Blob | null | null | Raw binary of the generated PDF. |
error | Error | null | null | Last render error, if any. |
loading | boolean | false | Whether a render is currently in flight. Starts as true when an initial document is passed. |
Updater
| Prop | Type | Default | Description |
|---|---|---|---|
update(document) | (document: DocumentTree) => void | — | Replaces the rendered document. Renders run through a concurrency-1 queue where a newly scheduled render replaces any pending one. |
Usage
usePDF takes a document tree — a plain object of { type, props, children } nodes — not a Vue component:
<script setup lang="ts">
import { usePDF } from '@vuepdf/renderer'
const [instance] = usePDF({
document: {
type: 'DOCUMENT',
props: { title: 'Hello' },
children: [
{
type: 'PAGE',
props: { size: 'A4' },
children: [
{ type: 'TEXT', props: {}, children: ['Hello, PDF!'] },
],
},
],
},
})
</script>
<template>
<div v-if="instance.loading" class="loading">Generating PDF...</div>
<iframe
v-else-if="instance.url"
:src="instance.url"
width="100%"
height="500px"
class="pdf-preview"
/>
</template>Updating on Data Changes
Call the updater whenever your data changes to re-render:
<script setup lang="ts">
import { usePDF } from '@vuepdf/renderer'
const [instance, update] = usePDF()
const buildTree = (invoice: { id: string; amount: number }) => ({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { size: 'A4' },
children: [
{
type: 'TEXT',
props: {},
children: [`Invoice ${invoice.id} — $${invoice.amount}`],
},
],
},
],
})
const invoice = ref({ id: '123', amount: 1500 })
// Re-render whenever the data changes; pending renders are replaced.
watchEffect(() => update(buildTree(invoice.value)))
</script>Prefer a Component Wrapper
Hand-writing trees is rarely what you want. PDFViewer, PDFDownloadLink, and BlobProvider each run usePDF internally and accept a slotted <Document>, so you can compose your PDF with the normal components. PDFViewer takes it in the default slot; the other two take it in a #document slot and keep the default slot for your own markup:
<script setup lang="ts">
import { PDFViewer } from '@vuepdf/renderer'
import InvoiceDoc from './InvoiceDoc.vue'
</script>
<template>
<PDFViewer :style="{ width: '100%', height: '500px' }">
<InvoiceDoc :invoice="invoice" />
</PDFViewer>
</template>usePDF directly only when you need to own the render loop — for example, driving a preview from a tree you build programmatically.