Documentation
Data & assets
Reactive data
The whole point of authoring in Vue is that your data drives the document. v-for, v-if, computed
and slots all work - the renderer walks the same tree Vue builds, so anything that produces a tree
produces a PDF.
<script setup lang="ts">
import { computed } from "vue";
import { Document, Page, Row, Text, Divider } from "@jasy/vue";
const props = defineProps<{ lines: { id: number; name: string; price: number }[] }>();
const total = computed(() => props.lines.reduce((sum, l) => sum + l.price, 0));
</script>
<template>
<Document :size="11">
<Page :size="'A4'" :margin="48" :gap="8">
<Row v-for="line in lines" :key="line.id" :justify="'between'">
<Text>{{ line.name }}</Text>
<Text>{{ line.price }} EUR</Text>
</Row>
<Divider />
<Row :justify="'between'">
<Text bold>Total</Text>
<Text bold>{{ total }} EUR</Text>
</Row>
</Page>
</Document>
</template>
Custom fonts
The standard PDF fonts (Helvetica, Times, Courier) need nothing. To use your own, register the font
bytes on <Document :fonts> under a name, then reference that name as a font:
<script setup lang="ts">
import { ref, onMounted } from "vue";
const font = ref<Uint8Array>();
onMounted(async () => {
font.value = new Uint8Array(await (await fetch("/fonts/Inter.ttf")).arrayBuffer());
});
</script>
<template>
<Document v-if="font" :fonts="{ Inter: font }" font="Inter">
<Page :size="'A4'" :margin="48">
<Text :size="24" bold>Set in Inter</Text>
</Page>
</Document>
</template>
A .ttf is loaded with full Unicode (the font is subsetted on the way into the PDF, so the file stays
small). For weights, register one file per style as { Inter: { normal, bold, italic } }.
Images
<Image :src> takes the image bytes as a Uint8Array. JPEG and PNG both work, and PNG transparency is
honoured (it composites over whatever sits behind it, not a white box). Fetch the bytes the same way as
a font:
<script setup lang="ts">
import { ref, onMounted } from "vue";
const logo = ref<Uint8Array>();
onMounted(async () => {
logo.value = new Uint8Array(await (await fetch("/logo.png")).arrayBuffer());
});
</script>
<template>
<Image v-if="logo" :src="logo" :width="120" :height="40" :fit="'contain'" />
</template>
In Node, read the file into a Uint8Array (for example with fs.readFileSync) and pass it the same
way.
Render options
renderToPdf (and renderToPdfString) take a third argument for engine options. The most useful is
onOverflow, which decides what happens when a single unbreakable element is taller than the page:
const bytes = await renderToPdf(Invoice, props, { onOverflow: "warn" });
"error"(default) - throw, so an impossible layout never slips out silently."warn"- place it anyway (clipped) and log."ignore"- place it anyway, no log.