Typst: The new foundation for documents

2 min read Original article ↗

Fuse content and scripting to make your documents reactive. In the realm of a Typst document, there is nothing you can’t automate.

= Markup <markup>
With built-in syntax for the most common document elements, Typst markup is designed to be pleasant to write and read:

- *Strong* and _normal_ emphasis
- A reference to @markup
- Math: $a, b in { 1/2, sqrt(4 a b) }$

But that's just the surface!

Document with the heading "1. Markup", a paragraph, a bullet point list with examples, and a second paragraph. The strong and normal emphasis in the first list item display as bold and italics. The `@markup` reference displays as "Section 2". The equation renders as two variables a and b being elements of a set consisting of a vertical fraction one half and the square root of 4 times a times b.

#set heading(numbering: "1.")
#show strong: set text(red)

= Styling
The asterisk syntax is just a shorthand for the `strong` function. And with *set* and *show rules,* you can style that emphasis however you like, separating content from formatting.

Document with the heading "2. Styling" followed by a paragraph. The word "strong" in "strong function" is displayed in a monospace font. The words "set" and "show rules" are bold and red.

= Scripting
Venture to go even further? Typst has powerful embedded scripting features such as conditionals, loops, functions, and methods.

#let count = 8
#let nums = range(1, count + 1)
#let fib(n) = (
  if n <= 2 { 1 }
  else { fib(n - 1) + fib(n - 2) }
)

#align(center, table(
  columns: count,
  ..nums.map(n => $F_#n$),
  ..nums.map(n => str(fib(n))),
))

Document with the heading "3. Scripting" followed by a paragraph and a table. The table contains eight columns and two rows. The first row contains the letter F with subscripts 1 to 8 (per cell) in mathematical style. The second row contains the corresponding Fibonacci number.

= Introspection <introspection>
A Typst document is self-aware! You can find things on the pages, measure their sizes, and more, giving you the tools to build rich automations.

#let find(l) = context [
  The element labelled
  #raw(repr(l)) is on slide
  #locate(l).page().
]

#find(<introspection>)

Document with the heading "4. Introspection" followed by two paragraphs. The second paragraph contains the text "The element labelled <introspection> is on slide 4." The word "<introspection>" is set in a monospace font.

= Data loading
Want to import some data for a table or plot? Or even generate a full document from a single JSON file? Typst has got you covered.

#for (day, data) in (
  "Monday": json("monday.json"),
  "Tuesday": json("tuesday.json"),
) [
  On #day, the temperature is
  #data.temperature~°#data.unit
  and it is #highlight(
    fill: (
      sunny: yellow,
      windy: aqua,
    ).at(data.weather),
    data.weather,
  ).
]

Document with the heading "5. Data loading" followed by two paragraphs. The second paragraph contains the text "On Monday, the temperature is 18.5 °C and it is sunny. On Tuesday, the temperature is 14.5 °C and it is windy." The word "sunny" is highlighted in yellow (text-marker style). The word "windy" is highlighted in a light blue (called aqua).