Browser API

PDFDownloadLink

Renders an <a> element whose href points at the generated PDF blob and whose download attribute carries your filename. It runs usePDF internally, so you never manage the render loop yourself.

Props

PropTypeDefaultDescription
documentDocumentTreeA prebuilt document tree ({ type, props, children }), for react-pdf API parity. Optional — prefer the document slot.
fileNamestring'document.pdf'Value of the anchor's download attribute.
document takes a plain document tree object. To compose your PDF with the usual components, use the document slot instead.

Slots

PropTypeDefaultDescription
documentslotYour <Document> component. Rendered into a hidden container; its assembled tree is handed to the internal pdf instance.
defaultscoped slotThe link label. Receives the render state: { url, blob, error, loading }.

Events

PropTypeDefaultDescription
click(event: MouseEvent, state: PDFState) => voidEmitted when the anchor is clicked, with the current render state as the second argument.

Usage

Slot your <Document> into the document slot and use the default slot for the label:

vue
<script setup lang="ts">
import { PDFDownloadLink } from '@vuepdf/renderer'
import MyDocument from './MyDocument.vue'
</script>

<template>
  <PDFDownloadLink file-name="report.pdf">
    <template #document>
      <MyDocument />
    </template>

    <template #default="{ loading }">
      {{ loading ? 'Preparing...' : 'Download PDF' }}
    </template>
  </PDFDownloadLink>
</template>

Reacting to Render State

The default slot is a scoped slot — the same state usePDF exposes:

vue
<template>
  <PDFDownloadLink file-name="invoice.pdf" class="btn">
    <template #document>
      <InvoiceDocument :invoice="invoice" />
    </template>

    <template #default="{ loading, error, url }">
      <span v-if="error">Failed to generate</span>
      <span v-else-if="loading || !url">Generating...</span>
      <span v-else>Download invoice</span>
    </template>
  </PDFDownloadLink>
</template>
The anchor is always rendered, even while loading is true. Until the first render finishes, href is empty — disable or relabel the link via the scoped slot if that matters for your UI.

With a Prebuilt Tree

For parity with react-pdf, you can pass a document tree directly instead of slotting a component:

vue
<script setup lang="ts">
const tree = {
  type: 'DOCUMENT',
  props: { title: 'Report' },
  children: [
    {
      type: 'PAGE',
      props: { size: 'A4' },
      children: [
        { type: 'TEXT', props: {}, children: ['Generated report'] },
      ],
    },
  ],
}
</script>

<template>
  <PDFDownloadLink :document="tree" file-name="report.pdf">
    <template #default="{ loading }">
      {{ loading ? 'Preparing...' : 'Download' }}
    </template>
  </PDFDownloadLink>
</template>

Attributes

The component sets inheritAttrs: false and forwards every extra attribute — classes, target, ARIA attributes — onto the underlying <a>:

vue
<template>
  <PDFDownloadLink
    file-name="report.pdf"
    class="btn"
    target="_blank"
    @click="onClick"
  >
    <template #document>
      <MyDocument />
    </template>
    <template #default>Download</template>
  </PDFDownloadLink>
</template>
PDFDownloadLink is browser-only. To produce a file on the server, use renderToFile or renderToStream.

See Also