# Satzstrom Primitives Reference

```sh

npm install @satzstrom/primitives

```

React components for pages, flowing content and document structure. Use ordinary HTML and CSS inside them.

## Document

`Document(props: DocumentProps)` is the document root. Its direct children must resolve to fixed `Page` or flowing `PageMaster` components; both can be combined. It defines language, reading direction, PDF metadata, and optional accessible labels.

| Prop         | Type                          | Meaning                                                 |
| ------------ | ----------------------------- | ------------------------------------------------------- |
| `children`   | `ReactNode`                   | Fixed pages and page masters.                           |
| `title?`     | `string`                      | Document title and PDF metadata; required for PDF/UA-1. |
| `author?`    | `string`                      | PDF author.                                             |
| `subject?`   | `string`                      | PDF subject.                                            |
| `keywords?`  | `string[]`                    | PDF search terms.                                       |
| `lang?`      | `string`                      | Document language; defaults to `de`.                    |
| `dir?`       | `"ltr" \| "rtl"`              | Reading direction; defaults to `ltr`.                   |
| `bookmarks?` | `SequenceDefinition<boolean>` | Sequence used for PDF bookmarks.                        |
| `labels?`    | `DocumentLabels`              | Overrides localized accessible labels.                  |
| `className?` | `string`                      | CSS class of the document root.                         |

```tsx
<Document title="Invoice 2026-0718" author="Brückner Studio" lang="en">
  <Page size="A4">…</Page>
</Document>
```

## Page

`Page(props: PageProps)` creates exactly one freely composed physical page. Its children can be static or a render function receiving `page` and `pages`. Standard HTML `section` attributes, such as `id` and `style`, can also be passed to `Page`. Its `children` prop accepts content or the render function.

| Prop           | Type                                        | Meaning                                                        |
| -------------- | ------------------------------------------- | -------------------------------------------------------------- |
| `children`     | `ReactNode \| ((PageContext) => ReactNode)` | Page content or page-value render function.                    |
| `size?`        | `PageSizeName \| { width; height }`         | Paper size; defaults to A4. Custom dimensions use millimetres. |
| `orientation?` | `"portrait" \| "landscape"`                 | Page orientation.                                              |
| `bleed?`       | `number`                                    | Non-negative bleed in millimetres.                             |
| `cropMarks?`   | `boolean`                                   | Enables crop marks.                                            |
| `className?`   | `string`                                    | CSS class of the physical page.                                |

## PageMaster

`PageMaster(props: PageMasterProps)` flows its children through as many pages as necessary. Without `layout`, the whole page is the flow area. A custom `layout` receives `page` and `pages` and must render exactly one `Flow` whose CSS box defines the available area on that page.

### Accessibility in a custom layout

Content inside `Flow` remains accessible. In the rendered layout, the highest branches outside it receive `aria-hidden="true"` automatically. An intentional accessible sibling branch can use `aria-hidden="false"`; explicit `aria-hidden="true"` always wins.

| Prop           | Type                             | Meaning                               |
| -------------- | -------------------------------- | ------------------------------------- |
| `children`     | `ReactNode`                      | Flowing content.                      |
| `layout?`      | `ComponentType<PageLayoutProps>` | Recurring page frame with one `Flow`. |
| `size?`        | `PageSettings["size"]`           | Paper size for generated pages.       |
| `orientation?` | `PageSettings["orientation"]`    | Shared orientation.                   |
| `bleed?`       | `number`                         | Bleed in millimetres.                 |
| `cropMarks?`   | `boolean`                        | Enables crop marks.                   |
| `className?`   | `string`                         | CSS class of generated pages.         |

```tsx
import {
  Document,
  Flow,
  PageMaster,
  type PageLayoutProps,
} from '@satzstrom/primitives';

function ReportPage({ page, pages }: PageLayoutProps) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      <header>Annual report</header>

      <Flow style={{ flex: 1 }} />

      <footer>
        {page} / {pages}
      </footer>
    </div>
  );
}

export default function Report() {
  return (
    <Document title="Report" lang="en">
      <PageMaster layout={ReportPage} size="A4">
        <h1>Report</h1>

        <p>Content that flows across pages.</p>
      </PageMaster>
    </Document>
  );
}
```

The layout above fills the page, then gives the empty `Flow` the remaining height through Flexbox. A custom layout must give its `Flow` a visible CSS box.

## PageBreak and RepeatBox

`PageBreak()` forces the following flowing content in a `PageMaster` to begin on a new page.

`RepeatBox` marks a box whose border, background, and padding repeat on every fragment while its content continues without duplication. Its optional `as` prop chooses the rendered element and defaults to `div`; remaining props are those of that element.

## Numbering, contents, and references

`defineSequence({ name, titleRequired? })` creates an immutable independent numbering system for chapters, figures, or tables.

`Sequence` registers an entry. Its required `sequence` prop selects the definition and its required render-function `children` receives `number`, `title`, and `depth`. Optional props are `id`, `title`, and the accessible `numberLabel`. A title is required when the definition uses `titleRequired: true`.

```tsx
const chapters = defineSequence({ name: 'chapters', titleRequired: true });

<Sequence sequence={chapters} id="results" title="Results">
  {({ number, title }) => (
    <h2>
      {number} {title}
    </h2>
  )}
</Sequence>;
```

`Contents` creates a contents list from a required `sequence`, including final numbers and pages. `className` styles the default list. With `asChild`, it passes `entries` to exactly one custom React element.

`Ref` links to the HTML ID in required `target` and displays `number`, `title`, or `page` through its optional `value`, which defaults to `number`. It also accepts `className`.

## Footnotes: complete document and migration

Documents with footnotes now require one empty `Footnotes` region. In each PageMaster layout that uses footnotes, add it outside `Flow`. If the PageMaster has no layout yet, use the frame below. For a fixed `Page`, place `Footnotes` inside that Page; overflow is reported instead of generating more pages.

Copy this complete example into `document.tsx` in a Satzstrom project. The full-height frame gives `maxHeight: "20%"` a definite reference. Footnotes grow up to that limit, and Flow gets the remaining space. Font, spacing and separators belong to your layout.

```tsx
import {
  Document,
  PageMaster,
  Flow,
  Footnote,
  Footnotes,
} from '@satzstrom/primitives';

function PageLayout() {
  return (
    <div
      style={{
        height: '100%',
        padding: '15mm',
        display: 'flex',
        flexDirection: 'column',
      }}
    >
      <Flow style={{ flex: 1, minHeight: 0 }} />
      <Footnotes
        style={{ maxHeight: '20%', flexShrink: 0, fontSize: '10pt' }}
      />
    </div>
  );
}

export default function Report() {
  return (
    <Document title="Report with footnotes" lang="en">
      <PageMaster size="A4" layout={PageLayout}>
        <h1>A report with footnotes</h1>
        <p>
          A statement with a source.
          <Footnote>Source: Annual report 2025.</Footnote>
        </p>
      </PageMaster>
    </Document>
  );
}
```

## Footnote and Math

`Footnote({ children, label? })` places a numbered call in the text and moves its content to the authored `Footnotes` region. Add one empty `<Footnotes />` outside Flow in the PageMaster layout or inside a fixed Page. Style it with CSS, including an optional max-height. Empty regions disappear; no separator or height limit is added. Long notes continue within the same PageMaster; fixed Pages report overflow. Markdown and JSX notes share numbering, placement and backlinks.

`Math({ children, display?, label? })` renders a KaTeX string as visible HTML and accessible MathML. `display` creates a separate equation row and `label` provides a stable accessible label.

## Markdown

`Markdown({ children, labels? })` renders GitHub-Flavored Markdown with tables, footnotes, and mathematics. Raw HTML is deliberately skipped.

## useRenderReady

`useRenderReady(ready: boolean)` delays measurement and rendering while asynchronous browser content is incomplete. Call it in the component that owns the asynchronous state. An outstanding wait is cleared when that component unmounts.

## Markdown navigation

- [CLI reference](/docs/cli.md)

- [MCP reference](/docs/mcp.md)

- [Quickstart](/quickstart.md)

- [Complete docs index](/docs/llms.txt)

- [Complete Markdown index](/llms.txt)

Markdown math uses `$...$` inline and `$$...$$` for display equations. Escape literal dollar signs as `\$`.

## Authoring details

Custom dimensions are in millimeters. With `{ width: 148, height: 105 }`, landscape stays 148 × 105 and portrait becomes 105 × 148. Without orientation the dimensions remain unchanged.

`Contents asChild` supplies `entries: SequenceEntry[]`. The complete entry type is `{ id: string; number: string; title?: string; page: number; depth: number; parentId?: string }`. Give the custom component optional entries with an empty default before pagination populates them.

Import fonts through ordinary package CSS, for example `import "@fontsource-variable/manrope"`, after installing the package in the document project. Relative font assets are resolved from their CSS file. Missing assets report their source and cause.

Page floats use `float: top` or `float: bottom` in a stylesheet, for example `.page-note { float: bottom; }`. They reserve space in Flow. Normal left/right float wrapping can differ after pagination; diagnosed limitations fail the strict check. Columns and fragmentable containers retain the supported CSS behavior; a required unsupported fragmentation produces a source diagnostic.

Media dimensions come from HTML/CSS. For responsive images, use `img { max-width: 100%; height: auto; }` and choose any required maximum height in the document layout. The engine does not silently rescale media.
