Guides

Typst: render a Document as a PDF with citations

The add-on @skaile/forge-editor-typst: the render target typst-pdf that turns a Document or a paper into Typst markup, writes the bibliography as BibTeX, and compiles a PDF in one of four citation styles.

The add-on @skaile/forge-editor-typst adds one render target, typst-pdf. It turns a whole Document, or one Typed block of the Block type paper, into a PDF made by Typst. The Cite nodes of the content become citations, and the Bibliographic records inside the content become the bibliography.

The add-on is server-side only. It needs no editor feature: the block action „Erzeugen als …“ and the command „Dokument erzeugen als …“ list every target of the render capability, this one among them.

Install and wire

import { createRenderer, markdownTarget } from '@skaile/forge-editor/adapters/render'
import { typstTarget } from '@skaile/forge-editor-typst'

// installEditorServer({ ports: { render } })
export const render = createRenderer([markdownTarget(), typstTarget({ style: 'apa', locale: 'de' })])
Option of typstTargetMeaning
stylecitation style when the render names none: one of CSL_STYLES, default apa
localelanguage of the PDF (hyphenation, the bibliography title) and of the error messages: de (default) or en
labelthe name in the export menu (default PDF (Typst))
acceptsBlock types accepted besides 'document' (default ['paper'])
compile{ engine?: 'auto' | 'node' | 'binary', binary?: string }, see below

A render input picks the style per request: options: { style: 'ieee' }.

The compiler

compileTypst tries two engines in this order:

  1. The native compiler @myriaddreamin/typst-ts-node-compiler, an optional dependency of the add-on. It runs inside the server process; no typst program is needed. The compile is synchronous and blocks the event loop while it runs.
  2. The typst program on the PATH (or compile.binary). The add-on writes main.typ and refs.bib to a temporary directory, runs typst compile, reads the PDF and removes the directory. A client that disconnects aborts the process.

When neither exists the render fails with the error code typst-missing. Markup that Typst rejects fails with typst-failed; the message holds Typst's own diagnostics. A style outside CSL_STYLES fails with bad-style before any compile starts. All three are TypstError with a stable code; the message is in the language of the render and reaches the client as the error event.

What the markup holds

typstOf(content, bib, style) is pure. It maps the content like the editor's Markdown export does:

ContentTypst
heading (level n)= repeated n times
Typed block (depth d)heading of level d with its title (not when the title is hidden), the description in #emph, the tags in small grey text, then the body
paragraph, hard breaktext; a break is \ and a newline
bold, italic, strike, underline, highlight, sub, super, code, link#strong, #emph, #strike, #underline, #highlight, #sub, #super, #raw, #link (the function form works inside a word, which *…* does not)
bullet, ordered and task lists- and 1. items, nested by indentation; a task item starts with ☐ or ☑
table#table with table.header for a header row, colspan and rowspan kept
code block, quote, rule#raw(block: true), #quote(block: true), #line
mention, tag, reference chiptheir text
image, audio, video, file, block embedthe kind and name in italics: the editor's asset URLs are not files Typst can read
cite node@key, or @key[locator]

A cite whose key names an entry of the bibliography becomes a Typst citation. A cite whose key names none reads as the text (key), like the editor's gone chip. When at least one citation resolved, the markup ends with #bibliography("refs.bib", style: …, title: …); Typst prints only the works that are cited. A bare @key followed by unmarked text that continues the word gets an empty content block (@key#[]), so Typst does not read the text as part of the key.

The bibliography

bibEntriesOf(content) collects the CSL-JSON record of every Typed block with meta.bib, in Document order, with the block id and the title. bibFileOf(entries) writes one BibTeX entry for each through the library's bibtexOf; the citation key is the one the cite node holds (bibtexKey). Two records that derive one key keep the first. The file is refs.bib, next to the main file.

StyleTypst style
apaAPA
ieeeIEEE
chicago-author-dateChicago author-date
vancouverVancouver

The styles are Typst's built-in CSL styles, so the add-on has no citation processor of its own.

Pieces for your own pipeline

ExportUse
typstTarget(options?)the RenderTarget
typstOf, typstSourceOfmarkup, or markup with its .bib text
bibEntriesOf, bibFileOf, BIB_FILEthe bibliography of a content tree
compileTypst, typstEngineOfthe PDF; which engine would run, or null
CSL_STYLES, isCslStylethe citation styles
TypstErrorthe error with its code
Copyright © 2026