> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openpdf.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Documents

> The file contract every open-pdf document follows: one component, meta, pageOptions, and the tw dialect.

A document is one folder under `docs/` with one entry file:

```
docs/<kebab-case-id>/
  index.tsx        # the whole document
  assets/          # optional: images and fonts this doc uses
```

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:

```tsx docs/q3-agreement/index.tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { type DocMeta, PageNumber, type PageOptions, TotalPages } from '@autono/open-pdf';

export const meta: DocMeta = {
  title: 'Q3 Services Agreement',
  createdAt: '2026-08-18T12:00:00Z',
};

export const pageOptions: PageOptions = {
  size: 'a4',
  margin: { top: 56, right: 64, bottom: 72, left: 64 },
  footer: (
    <div tw="flex w-full justify-center text-[9px] text-slate-400">
      <span tw="flex">
        Page <PageNumber /> of <TotalPages />
      </span>
    </div>
  ),
};

export default function Document() {
  return (
    <main tw="flex flex-col text-[12px] leading-relaxed text-slate-800">
      {/* flowing content */}
    </main>
  );
}
```

### 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](/authoring/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](/authoring/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](/authoring/fonts-and-images).

## The dialect: HTML-shaped JSX + `tw`

Write the HTML you already know, styled with Tailwind utilities via the `tw` prop:

```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
<div tw="mt-6 flex items-baseline justify-between border-b border-slate-200 pb-2">
  <h2 tw="text-[18px] font-bold text-slate-900">Deliverables</h2>
  <span tw="text-[10px] uppercase tracking-widest text-slate-400">Section 2</span>
</div>
```

* 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.

| Element                     | Size       |
| --------------------------- | ---------- |
| Document title              | 24 to 34px |
| Section heading             | 15 to 20px |
| Body text                   | 11 to 13px |
| Table body, dense data      | 10 to 11px |
| Caption, legal, footer band | 8 to 10px  |

* 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.

<Note>
  There is no vertical budget. Content flows and the engine adds pages. What you control is where breaks happen. Read [Pagination](/authoring/pagination) before writing any doc longer than a page.
</Note>

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](/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:

```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
const phases = [
  { phase: 'Discovery', weeks: '1-2', fee: 14800 },
  { phase: 'Build', weeks: '3-8', fee: 86400 },
];

{phases.map((p) => (
  <tr key={p.phase} tw="border-b border-slate-200">
    <td tw="p-2 align-top font-bold">{p.phase}</td>
    <td tw="p-2 align-top">{p.weeks}</td>
    <td tw="p-2 text-right align-top">{money(p.fee)}</td>
  </tr>
))}
```

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:

```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
const KeyValue = ({ label, value }: { label: string; value: string }) => (
  <div tw="flex justify-between border-b border-slate-100 py-1.5">
    <span tw="text-slate-500">{label}</span>
    <span tw="font-bold">{value}</span>
  </div>
);

<KeyValue label="Client" value="Harborline Logistics Inc." />
<KeyValue label="Term" value="September 1 to November 21, 2026" />
<KeyValue label="Model" value="Fixed fee per phase, net 30" />
```

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](/inspector).

## Next

<CardGroup cols={2}>
  <Card title="Tables" icon="table" href="/authoring/tables">
    Real table markup, column tracks, and repeated headers.
  </Card>

  <Card title="Pagination" icon="scissors-line-dashed" href="/authoring/pagination">
    Page breaks, keep-together blocks, and running bands.
  </Card>

  <Card title="Fonts and images" icon="type" href="/authoring/fonts-and-images">
    Assets, custom fonts, and glyph coverage.
  </Card>

  <Card title="Themes" icon="palette" href="/authoring/themes">
    Reusable visual identities under themes/.
  </Card>
</CardGroup>
