Server-side JSX · no dependencies

PDF invoices with JSX

JSX isn't tied to HTML. Compose a PDF from components, just like a page, and let a tiny writer turn it into bytes. Edit the invoice below and watch the PDF update.

Customer

Items

DescriptionQtyPrice €
invoice.pdf

How it works

  1. JSX builds a tree

    jsx-async-runtime turns every element into a plain object like { tag, props }, which doesn't have to become HTML.

  2. renderPdf() walks it

    It calls components (also async ones, with this as context) and collects drawing primitives like <Text> and <Rect>.

  3. pdf.js writes the bytes

    Numbered objects, operators like BT /F1 10 Tf … Tj ET and a table of byte offsets, returned by the route as a Response.

InvoicePdf.jsxJSX
function AmountDue({ gross, due }) {
  return (
    <View x={270}>
      <Rect width={229} height={96} fill="#6d28d9" radius={10} />
      <View x={18} y={24}>
        <Text size={7.5} bold color="#ddd6fe">
          AMOUNT DUE
        </Text>
        <Text y={32} size={24} bold color="#ffffff">
          {euro.format(gross)}
        </Text>
        <Text y={54} size={9} color="#ddd6fe">
          Please pay by {formatDate(due)}
        </Text>
      </View>
    </View>
  );
}
<Document title>
The root element of the PDF.
<Page>
Starts a new A4 page.
<View x y>
Moves its children, so components draw relative to their own origin.
<Text x y size bold color align>
One line of Helvetica text.
<Rect … radius>
A box, filled or stroked, with optional rounded corners.
<Circle cx cy r>
A circle, drawn with four Bézier curves.
<Line x1 y1 x2 y2>
A straight line.