How do I get the outline/table of contents/toc to play nice with `show heading`?

This is fine

#set heading(numbering: "I")
#show heading: it => {
  counter(heading).display(it.numbering)
}

= asdf

= sadf

= asd

adding the outline causes a compile error, complaining that it.numbering is none. How can I work around this, preferably without moving the outline call before the heading show rule?

#set heading(numbering: "I")
#show heading: it => {
  counter(heading).display(it.numbering)
}

#outline()

= asdf

= sadf

= asd

Answered on discord #quick-questions at Discord. Too long didn’t read: if it.numbering != none { ... }.

Too short, want more:

Discord transcript

:fire:PgSuper​:fire: 1/6/2026 5:32 PM

if it.numbering != none { ... }

saffronner 1/6/2026 5:32 PM

d’oh

smhmh

wonder why the outline inner code apparently produces no numbering though… doesn’t matter too much now

:fire:PgSuper​:fire: 1/6/2026 5:33 PM

look above it…

saffronner 1/6/2026 5:34 PM

ahhhh, my mental model said outline somehow called the heading function to generate headings and their numberings, but i guess not?

:fire:PgSuper​:fire: 1/6/2026 5:35 PM

?r

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

#outline()

= asdf

= sadf

= asd

Typst-RendererAPP 1/6/2026 5:35 PM

  1. :fire:PgSuper​:fire: 1/6/2026 5:35 PM

that should clarify

:p

saffronner 1/6/2026 5:35 PM

hey lookit that :p

thx

:fire:PgSuper​:fire: 1/6/2026 5:36 PM

it only uses the heading function for the word “contents” (the title)

cuz like , if it used headings to create the heading outline, the outline would be infinite

haha

okay but despite that, semantically it doesnt make much sense anyways, you dont have any section titles in your outline

but it uses outline.entry

so , if you want to modify the outline, you can use that

for example, to add some cool colored blocks on level 1 outline entries

with outline.entry.where(level: 1)

ive done this on my own template because fancy colored blocks are, well, fancy

?r

#set heading(numbering: "1.")
#show heading: set text(red)
#show outline.entry.where(level: 1): set text(white, weight: "bold")
#show outline.entry.where(level: 1): block.with(fill: red, inset: 5pt)

#outline()

= asdf

== sadf

= asd

== sadf

Typst-RendererAPP 1/6/2026 5:38 PM

You can just change the selector as shown in How to avoid ghost numbering in headers? - #5 by Andrew.

#show heading.where(outlined: true): it => {
  counter(heading).display(it.numbering)
}

This is a bit shorter too, though it’s 81 chars long, so it’s a bit too long to put on one line.