Documentation

PDFs in Vue

@jasy/vue lets you author a PDF the way you build an app: a tree of components, with props, slots and your reactive data. It is a thin Vue custom renderer over the @jasy/pdf engine, so you get its real layout and pagination - and because the engine is isomorphic, renderToPdf produces the PDF bytes right in the browser. No headless browser, no server round-trip, no Java.

If you have used @react-pdf/renderer on the React side this will feel familiar, with one difference: the same call also runs entirely client-side.

Install

pnpm add @jasy/vue@alpha vue

vue is a peer dependency, and @jasy/pdf comes along automatically. You import everything you need - the components and the render function - from @jasy/vue.

Import the components

Import the ones you need from @jasy/vue. In Vue you are in charge of what is in scope, so a name like Text or Image never clashes with another library:

<script setup lang="ts">
import { Document, Page, Text } from "@jasy/vue";
</script>

Using it in Nuxt? The @jasy/nuxt module auto-registers the components (no imports) and can prefix them to dodge clashes.

Your first PDF component

A document component's root is always <Document>. Everything else nests inside, exactly like the engine's element tree.

<!-- Invoice.vue -->
<script setup lang="ts">
import { Document, Page, Row, Box, Text, Divider } from "@jasy/vue";

defineProps<{ customer: string; total: number }>();
</script>

<template>
  <Document :size="11" color="#1f2937">
    <Page :size="'A4'" :margin="48" :gap="16">
      <Text :size="24" bold color="#0a2348">Invoice #2026-001</Text>
      <Text color="#64748b">Billed to: {{ customer }}</Text>
      <Divider color="#e2e8f0" />

      <Row :justify="'between'">
        <Text>Consulting</Text>
        <Text bold>{{ total }} EUR</Text>
      </Row>

      <Box bg="#0a2348" :padding="12" :radius="6">
        <Text color="#f3dc29" bold>Total due: {{ total }} EUR</Text>
      </Box>
    </Page>
  </Document>
</template>

Render it to a PDF

renderToPdf takes the component (and optional props) and returns the PDF as a Uint8Array. This runs in the browser as happily as in Node - the same line of code.

<script setup lang="ts">
import { renderToPdf } from "@jasy/vue";
import Invoice from "./Invoice.vue";

async function download() {
  const bytes = await renderToPdf(Invoice, { customer: "ACME GmbH", total: 1190 });
  const url = URL.createObjectURL(new Blob([bytes], { type: "application/pdf" }));
  window.open(url);
}
</script>

<template>
  <button @click="download">Download invoice</button>
</template>

Need the raw PDF string instead of bytes? Use renderToPdfString. On a server, write the bytes to a file or stream them as a response - it is the same renderToPdf.

Where to next

  • Components - the full set, their props and the <Page> header / footer slots.
  • Data & assets - reactive data, custom fonts and images.
  • Creating PDFs - the underlying engine, its layout primitives and pagination.
jasypdf

Declarative PDFs in pure TypeScript. ZUGFeRD & XRechnung compliant, with no headless browser and no Java.

Resources

© 2026 Florian Heuberger · MIT License

Built with Nuxt · self-hosted fonts · no trackers