Automette docs
Templates

Add fields to a Typst template

Fields are the parts of a Typst template that change from one document to the next. For the full list of field types, see Typst field types.

Declare the fields

Put a #let data = (...) block at the top of the template, with one line per field. The value after each name is sample text: it shows in the editor's preview and nowhere else. A field that is left empty when you generate prints blank (Blank values).

#let data = (
  recipient: "Alice Johnson",
  issue_date: "15 Jan 2026",
  amount: "5000",
)

Hello, #data.recipient. Your invoice for #data.amount is due on #data.issue_date.

Use a field anywhere in the template as #data.name.

Choose the type of box

Add a comment after a field to set the box people fill in on the Generate page and in forms:

#let data = (
  recipient: "Alice Johnson",       // @type: text
  notes: "Payment due on receipt",  // @type: textarea
  paid: "false",                    // @type: boolean
  website: "https://example.com",   // @type: url
  issue_date: "15 Jan 2026",        // @type: date @format: DD MMM YYYY @label: Issue date
)

@label sets the text shown above the box. Without a comment, the type is guessed from the field's name.

Add a date

A date needs a format, or it is a plain text box. With @format, people pick the date from a calendar and the template receives it written in that pattern:

issue_date: "15 Jan 2026",  // @type: date @format: DD MMM YYYY

The format tokens are listed in Typst field types.

Do calculations with numbers

Every value arrives as text. Convert it before calculating:

#let total = float(data.amount) * 1.2
Total with tax: #total

Add a colour

A colour arrives as a hex value. Wrap it in rgb():

#let data = (
  brand_color: "#1a56db",  // @type: color
)

#rect(fill: rgb(data.brand_color), width: 100%)

Add an image

An image field lets people upload a picture or paste a link to one:

#let data = (
  logo: "logo.png",  // @type: image
)

#image(data.logo, width: 80pt)

Upload the sample image in the editor's Assets tab, so the preview can show it.

Add a list, such as line items

A list field holds rows that people can add and remove. Write the sample rows as a list and name the columns with @columns:

#let data = (
  items: (  // @type: array @columns: desc:text,qty:number,amount:number
    (desc: "Widget A", qty: "2", amount: "1200"),
    (desc: "Service fee", qty: "1", amount: "500"),
  ),
)

Loop over the rows:

#for item in data.items [
  #item.desc: #item.qty × #item.amount
]

Or put them in a table:

#table(
  columns: (1fr, auto, auto),
  table.header([Description], [Qty], [Amount]),
  ..data.items.map(item => ([#item.desc], [#item.qty], [#item.amount])).flatten()
)

Keep at least one sample row, so the preview shows the table.

Older templates that store lists as JSON

Some older templates keep a list as JSON text (@type: json) and read it with json(bytes(data.items)). That still works. A template that calls json.decode(...) fails with function json does not contain field decode: replace the call with json(bytes(...)). For new templates, use a list field as above.

Last updated on

On this page