Typst Counters
Built-in counters for pages, headings, figures, tables, equations. Custom counters for anything else. Access with #counter(...).
Built-in counters
| Counter | Tracks |
|---|---|
| #counter(page) | Current page number |
| #counter(heading) | Heading numbering |
| #counter(figure) | Figure numbering |
| #counter(figure.where(kind: table)) | Table numbering |
| #counter(math.equation) | Equation numbering |
| #counter(footnote) | Footnote numbering |
Display the current page number
// In a footer
#set page(
footer: align(center)[
Page #counter(page).display()
],
)
// As Roman numerals
#counter(page).display("I") // I, II, III
// As letters
#counter(page).display("A") // A, B, C"Page X of Y" footer
#set page(
footer: context align(center)[
Page #counter(page).display() of #counter(page).final().at(0)
],
)Note the context — needed because final() requires evaluation context.
Reset / change page numbering
// Front matter: Roman numerals starting from i
#set page(numbering: "i")
#counter(page).update(1)
... title page, TOC, abstract ...
// Main matter: Arabic numerals starting from 1
#set page(numbering: "1")
#counter(page).update(1)
... chapters ...Custom counter
#let definition-counter = counter("definition")
#let definition(body) = {
definition-counter.step()
block(stroke: 0.5pt, inset: 8pt)[
*Definition #context definition-counter.display():*
#body
]
}
#definition[A natural number is...] // Definition 1
#definition[A prime number is...] // Definition 2Reset figure counter at appendix
// In appendix section
#counter(figure).update(0)
#counter(heading).update(0)
#set heading(numbering: "A.1") // appendix-style numbering
= First Appendix Section // A.
#figure(image("..."), caption: [...]) // Figure A.1
#figure(image("..."), caption: [...]) // Figure A.2TypeTeX is a free in-browser Typst editor — experiment with counters and see updates instantly.
Try TypeTeX freeFrequently Asked Questions
A counter is a number that increments automatically as you write — like LaTeX's counters. Built-in counters track pages, headings, figures, tables, equations, and footnotes. You can also create custom counters for chapters, definitions, exercises, etc. Access them via the #counter() function.
#counter(page).display() returns the current page number. Often used in headers/footers: #set page(footer: align(center)[#counter(page).display()]). The .display() converts the internal number to displayable content.
#counter(page).update(0) sets the page counter to 0 (so the next page is 1). #counter(figure).update(0) restarts figure numbering. Often used at the start of a new section: appendix figures restart at A.1, etc.
#counter("my-counter").step() increments by 1. .update(n => n + 5) for arbitrary updates with a function. Most users don't need this — built-in counters auto-increment from headings, figures, etc.
#let mycount = counter("mycount"). Then #mycount.step() to increment and #mycount.display() to show. Useful for: definition counters in math papers, exercise counters in textbooks, custom labeled blocks.
Pass a numbering pattern: #counter(page).display("I") for I, II, III. Other patterns: "i" for lowercase Roman, "a" for letters, "A" for uppercase letters, "1" for default Arabic. Used in front matter pagination (Roman pages before main matter).
#counter(page).display() of #counter(page).final().at(0). The .final() returns the final value (the last page in the document). Combine: 'Page 3 of 12'. Common pattern in thesis footers.
#counter(heading).display() returns the current heading number. To show only level 1: #counter(heading).at(here()).first() — or use specific accessor methods. Most users just rely on heading numbering directly via #set heading(numbering: ...).
Yes: #context counter(figure).get().first() returns the current figure number. The #context block evaluates lazily — necessary for counters because they're location-dependent. Without #context, the value is 'unknown' at the time of compilation.