Typst Show Rules
#show is how you customize ANY element in Typst. Heading styling, figure layouts, link colors, table rendering — all one mechanism.
The pattern
#show <selector>: <transformation>
// Transformation can be a single function:
#show heading: set text(weight: "bold", size: 14pt)
// Or a function that takes the element and returns content:
#show heading: it => {
v(1em)
text(weight: "bold", size: 14pt, fill: blue, it.body)
v(0.5em)
}Common patterns
Chapter on new page
#show heading.where(level: 1): it => {
pagebreak(weak: true)
v(2em)
text(size: 24pt, weight: "bold", it.body)
v(1em)
}Caption above figures (instead of below)
#show figure: it => {
block(breakable: false)[
#it.caption
#it.body
]
}Style links
#show link: set text(fill: rgb("#1A73E8"))
// Or with underline
#show link: it => underline(text(fill: rgb("#1A73E8"), it))Custom citation rendering
// Make citations show in red (for visual debugging)
#show cite: set text(fill: red)
// Or wrap in brackets manually
#show cite: it => [(#it)]Number raw code blocks
#show raw.where(block: true): it => {
block(
fill: luma(240),
inset: 8pt,
radius: 4pt,
it,
)
}#set vs #show — when to use which
| Use case | Use |
|---|---|
| Set heading numbering format | #set |
| Make all headings bold | #set or #show |
| Add page break before each chapter | #show |
| Reorder figure caption + body | #show |
| Set default page size | #set |
| Wrap raw blocks in colored boxes | #show |
Rule of thumb: #set for parameter values, #show for transforming the element's rendering.
TypeTeX is a free in-browser Typst editor — write a show rule, see it apply across your document instantly.
Try TypeTeX freeFrequently Asked Questions
#set changes the default values of an element type's parameters: #set heading(numbering: "1.") makes all headings numbered. #show is more powerful — it transforms how an element renders by passing it through a function: #show heading: it => { v(1em); text(weight: "bold", it.body) }. Use #set for parameter changes, #show for layout/structural changes.
Use .where() to filter: #show heading.where(level: 1): it => { ... }. Other levels are unchanged. You can chain conditions: heading.where(level: 1, numbering: "1.").
#show heading.where(level: 1): it => { pagebreak(weak: true); it }. The 'weak: true' avoids inserting an extra page if we're already at the start of one. Place this rule once at the top of your document; every level-1 heading will trigger.
#show figure: it => { ... }. Inside, you can re-arrange the figure's components: it.body (the content), it.caption (the caption), it.numbering. For example, to put captions above figures: #show figure: it => block[#it.caption #it.body].
#show link: set text(fill: rgb("#1A73E8")). This applies a text color to all link content. Combine with underline or other formatting: #show link: it => underline(text(fill: blue, it)).
Yes. Stack them: #show heading.where(level: 1): ..., #show heading.where(level: 2): ..., #show figure: ..., etc. Each rule applies to matching elements. Order matters when rules could compete; later rules can override earlier ones.
Templates package up #show + #set rules into reusable functions. #import "@preview/template:1.0": * imports a template, then #show: template.with(...) applies all its rules to your document. Most academic templates expose configuration as named parameters of the .with() call.
Yes. Use #if conditions outside the #show definition: #if mode == "thesis" { show heading.where(level: 1): chapter-style }. Or inside the rule's body: #show heading: it => if it.level == 1 { ... } else { ... }.
'it' is the matched element being styled. For a heading, it.body is the heading text, it.level is 1/2/3, it.numbering is the number. The function in the show rule receives 'it' and returns the rendered version. Think of it as a transformer: input element → output styled content.