Skip to main content
A document is one folder under docs/ with one entry file:
That is the entire footprint. Helper components and constants live inside index.tsx. No sibling files, no CSS files, no extra dependencies. Only react, @autono/open-pdf, and plain JavaScript are available. A document is not a web page and not a slide deck. It renders to a real PDF, and the preview in the browser is the same bytes a reader downloads. Content flows top to bottom and the engine paginates it. You write flowing, print-shaped content; the engine owns pages.

The file contract

index.tsx exports exactly three things:
docs/q3-agreement/index.tsx

The default export

One zero-prop React component containing the whole document as flowing content. Not an array of pages, not one component per page. The engine decides where pages break; you influence it with the tools on Pagination. Components must be pure and synchronous. No hooks, no state, no window or document, no fetch, no Date.now() in render. The document renders in a web worker to static PDF bytes, so anything dynamic has nowhere to run.

meta

  • title (optional) shows in the doc header and browser tab. Defaults to the folder name.
  • createdAt (optional) is an ISO 8601 string literal, set once when the doc is scaffolded and used to sort the doc list. Keep it a plain string literal. The framework reads it with a regex and never evaluates the module to get it.
  • theme (optional) marks the doc as built from a theme under themes/. The id must match a theme’s <id>.md basename. See Themes.

pageOptions

Optional. Sets page size, margins, running header/footer bands, and custom fonts. Defaults: a4, 48px margins, no bands, the engine’s bundled font.
  • size is a preset string ('a4', 'letter', 'legal', …) or { width, height } in CSS px.
  • margin is a single value or a per-side object. Each value is a number (CSS px) or 'auto', never a CSS length string. '1cm' fails the render. A side set to 'auto' sizes itself to fit that side’s band.
  • header and footer render on every page, inside the margin. <PageNumber /> and <TotalPages /> only work inside these bands, never in body content.
  • fonts registers per-document fonts. See Fonts and images.

The dialect: HTML-shaped JSX + tw

Write the HTML you already know, styled with Tailwind utilities via the tw prop:
  • Elements: div, span, p, h1 to h3, table, ul/li, main, section, img, inline <svg>.
  • tw, not className. className is silently stripped.
  • Use style={{ ... }} for the handful of properties Tailwind can’t express: { breakBefore: 'page' }, { breakInside: 'avoid' }.
  • Arbitrary values are the norm for print sizing: text-[11px], w-[260px], p-[6px].
  • Bare strings and numbers are valid children anywhere, no wrapper element needed.
  • Inline <svg> renders as vector paths, good for rules, marks, and simple charts.
  • No external CSS, no <style> blocks.

Page geometry and the print type scale

Sizes are CSS pixels at 96 dpi. An A4 page is 794 × 1123 px, inside which your margins carve the text column. With the starter margins above you get roughly 666 px of width. Design for that column.
  • Line-height: 1.3 to 1.4 for headings, 1.4 to 1.7 for body.
  • One document, one palette: one text color, one muted, one accent, one rule tint.
  • Space between blocks: mt-4 to mt-10. Generous white space reads as professional print.
There is no vertical budget. Content flows and the engine adds pages. What you control is where breaks happen. Read Pagination before writing any doc longer than a page.
Web-scale typography (16px+ body) is the most common mistake. Print body is 11 to 13px.

Data rows vs designed repeats

Two shapes of repetition, two different rules. The distinction matters because the inspector maps clicks on the PDF back to source JSX. Tabular data belongs in a .map over a data array. Invoice line items, schedules, roster rows. Put the data in a typed const at the top of the file and keep the row JSX in the map body:
This is the one shape where a shared source location is correct: a comment on any row means “this row template”. Designed repeats are explicit instances. Feature cards, testimonial blocks, KPI tiles: define a small helper component in the same file and write one JSX call per item, data as props:
Explicit instances give each card its own source address, so “make the middle one green” is one edit, not three.

What you get for free

  • The home page lists every folder under docs/, with a live first-page preview per card.
  • The doc view renders the actual PDF: page scroll, thumbnail rail, page count and render time, and a Download button that produces a clean render without inspector metadata.
  • Hot reload: save index.tsx and the PDF re-renders in well under half a second.
  • Inspect mode (i) for click-to-source and comments. See The inspector.

Next

Tables

Real table markup, column tracks, and repeated headers.

Pagination

Page breaks, keep-together blocks, and running bands.

Fonts and images

Assets, custom fonts, and glyph coverage.

Themes

Reusable visual identities under themes/.