On this page

Your first PDF.

Create a project

Install Satzstrom and create a project. Its dependencies are installed for you.

Requires Node.js 20 or newer on Windows x64 or Linux x64.

Terminal
npm install -g satzstromsatzstrom init my-document

What’s in your project

A document is an ordinary React project. Add components, hooks and libraries as you need them.

Project files
my-document/├─ document.tsx   React document├─ styles.css     Document styles├─ package.json   Project dependencies└─ tsconfig.json  TypeScript configuration
document.tsx
Exports the React component that describes your document.
styles.css
Controls typography, spacing and layout. Import it from your document or its components.
package.json
Holds your project dependencies, including @satzstrom/primitives.

Open the preview

Your document opens in the browser. The first run completes the required setup automatically.

Terminal
cd my-documentsatzstrom dev document.tsx

Make it yours

Edit document.tsx and styles.css. The preview updates as you work. Here is a complete, one-page document to start with.

Page creates a fixed page. For content that needs to flow over several pages, use PageMaster.

document.tsx
import "./styles.css";import { Document, Page } from "@satzstrom/primitives";export default function MyFirstDocument() {  return (    <Document title="My first document" lang="en">      <Page size="A4">        <h1>My first document</h1>      </Page>    </Document>  );}

Create the PDF

In the browser preview, choose Check and review any reported issues. Then choose Create PDF. You can also run the commands below in a second terminal. Strict mode stops on layout warnings.

The PDF is saved as document.pdf beside your source file, with the same page breaks as the preview.

Terminal
satzstrom check document.tsx --strictsatzstrom render document.tsx --strict

Let content flow across pages

Use Page for a single, fixed page. Use PageMaster when the content should continue across as many pages as it needs. Both can appear in the same document.

Here, the page layout repeats an annual-report header and a page count. The article flows through the space between them.

document.tsx
import "./styles.css";import {  Document,  Flow,  PageMaster,  type PageLayoutProps,} from "@satzstrom/primitives";function ReportPage({ page, pages }: PageLayoutProps) {  return (    <div      style={{        display: "flex",        flexDirection: "column",        height: "100%",        padding: "20mm",        boxSizing: "border-box",      }}    >      <header>Annual report</header>      <Flow style={{ flex: 1 }} />      <footer>        Page {page} of {pages}      </footer>    </div>  );}export default function Report() {  return (    <Document title="Annual report" lang="en">      <PageMaster size="A4" layout={ReportPage}>        <h1>Annual report</h1>        <p>This content flows automatically across all required pages.</p>      </PageMaster>    </Document>  );}
PageMaster
Creates each required page using your layout. Its children are the content that flows through those pages.
Flow
Marks the content area in the layout. Here, flex: 1 gives it the space between the header and footer.
page / pages
The current page number and the total page count, supplied to the layout.

Add more paragraphs inside PageMaster and watch the preview grow. You edit the content; Satzstrom calculates where the pages break.

Number chapters and build a table of contents

Define the chapters once. Their numbers, contents entries and PDF bookmarks all follow the same structure.

document.tsx
import "./styles.css";import {  Contents,  Document,  PageMaster,  Ref,  Sequence,  defineSequence,} from "@satzstrom/primitives";const chapters = defineSequence({  name: "chapters",  titleRequired: true,});export default function Report() {  return (    <Document bookmarks={chapters}>      <PageMaster size="A4">        <h1>Annual report</h1>        <Contents sequence={chapters} />        <Sequence sequence={chapters} id="revenue" title="Revenue">          {({ number, title }) => <h2>{number}. {title}</h2>}        </Sequence>        <p>Revenue increased compared with the previous year.</p>        <Sequence sequence={chapters} title="Outlook">          {({ number, title }) => <h2>{number}. {title}</h2>}        </Sequence>        <p>          Building on chapter <Ref target="revenue" />,          we expect further growth in the coming year.        </p>      </PageMaster>    </Document>  );}
defineSequence
Creates the shared chapter sequence. titleRequired makes every chapter supply a title.
Sequence
Registers a chapter and supplies its calculated number and title to your component.
Contents
Lists those chapters with their final page numbers.
bookmarks
Uses the same sequence for the PDF viewer’s navigation.
Ref
Links to the chapter’s id. It can display the chapter number, title or page number.

Insert another chapter before Revenue. Its number, contents entry and the reference in Outlook update together.

Use existing Markdown

Markdown becomes semantic HTML inside your React document. Combine it with your own components, including tables, footnotes and mathematics.

document.tsx
import {  Document,  Markdown,  Page,} from "@satzstrom/primitives";export default function Report() {  return (    <Document>      <Page size="A4">        <Markdown>{`# Project status- Design complete- Release prepared`}</Markdown>      </Page>    </Document>  );}