Skip to main content
Typst is extremely powerful, but its syntax might feel unfamiliar to frontend developers at first glance. Don’t panic: If you know HTML, CSS (Flexbox/Grid), and JavaScript, you will love Typst. In PDFDyno, you receive your dynamic data via the data field in your JSON request. The backend automatically injects this data into your template as a #data variable. Here is how you translate the most important web concepts:

1. Rendering Variables from JSON (like JSX)

Instead of using {data.name} like in React/JSX, Typst uses a # to evaluate logic and variables.

2. Layouts: Flexbox and CSS Grid

Typst completely drops the concept of <div style="display: flex">. Instead, you use native functions like #grid() or #stack().

Columns side-by-side (CSS Grid / Flex-Row)

If you want to place two elements next to each other (e.g., billing address and date), use #grid.
template.typ

Elements stacked vertically (Flex-Col with Gap)

template.typ

3. Iterating over Arrays (.map in JS)

You have an array of invoice items in your JSON and want to render them in a table. Typst supports for loops and the .map() function on arrays.

4. Basic Styling (CSS -> Typst)

Styling in Typst is applied either globally via #set or locally as a function like #text().
template.typ

5. Common Pitfalls

When coming from HTML, there are a few Typst-specific quirks you need to watch out for.

Escaping @ and #

Typst uses # for logic and @ for references/citations. If you need to print a literal @ (e.g., in an email address) or # (e.g., for a hashtag), you must escape them with a backslash.

Umlauts and Special Characters in JSON

Ensure your JSON strings are properly UTF-8 encoded. Typst handles Unicode perfectly, but if your JSON parser sends malformed encoding (e.g., Müller instead of Müller), the PDF will render exactly that.

6. Common Developer Questions

How do I force a page break?

Typst automatically handles pagination, but if you want to explicitly start a new page (e.g., before an appendix or a new section in a report), simply use #pagebreak().