How to style table of contents with bold first-level entries and no dots?

I’m trying to create a table of contents with specific formatting requirements:

  • First-level headings should be bold and have no dots between the title and page number
  • Second-level headings and below should have normal weight and include dots as separators

Here’s what I want to achieve:

  • Level 1 entries: Bold text without dots before page number
  • Level 2+ entries: Normal text with dots (…) before page number

My current code:

//Inhaltsverzeichnis
#pagebreak()
#text(size: 16pt, weight: "bold")[Inhaltsverzeichnis]
#v(10mm)
#outline(
  title: none,
  indent: auto
)

This creates a basic table of contents, but I’m not sure how to apply different styling to different levels. I’ve looked at the outline documentation but couldn’t figure out how to conditionally format entries based on their level.

Here’s my reference image showing what I want to achieve:

Any help on how to customize the outline entries based on their hierarchy level would be appreciated!

You can use the following code to achieve your requirement:

// without dots
#show outline.entry.where(level: 1): set outline.entry(fill: [])
// bold text
#show outline.entry.where(level: 1): set text(weight: "bold")

Here is an example of usage:

code
#show outline.entry.where(level: 1): set outline.entry(fill: [])
#show outline.entry.where(level: 1): set text(weight: "bold")
#set heading(numbering: "1.1.1.1")

#outline()


= Test1

== Test11

=== Test111

= Test2

== Test21

=== Test211

== Test22

Rendering result:

explain

You can use the where method to filter the elements you want to modify when using the show rule. Here, you need to modify the entries with level 1 in the outline, so it is outline.entry.where(level: 1).
The following are specific requirements. For example, if you do not use dots, you only need to set the fill of the outline entry to [] or none. To set the font to bold, you only need to set the text weight.

1 Like

Although it’s easier to do manually in Typst 0.13 than previously (see @kands_code’s reply), outrageous – Typst Universe is still a useful package for this. Note that it also aligns all the dots in the outline, something that Typst doesn’t do out-of-the-box.

4 Likes

Shameless plug, the latex-lookalike package does precisely this.

Usage:

#import "@preview/latex-lookalike:0.1.1" // NOTE: use version 0.1.2 when released to fix outline title for languages other than English.

#set text(lang: "de")

#set heading(numbering: "1.1")

// Style outline as LaTeX "Table of contents".
#show: latex-lookalike.style-outline

#outline()

= foo

// etc, ...

Output:

Edit 1: an issue with the outline title for other languages than English was fixed in version 0.1.2 of latex-lookalike (in 0.1.1 it always renders as “Table of contents”, in 0.1.2 it will render as “Inhaltsverzeichnis” or whatever is the default for the current language). The PR to merge v0.1.2 into Typst Universe is latex-lookalike:0.1.2 by mewmew · Pull Request #2624 · typst/packages · GitHub

Edit 2: Thank @SillyFreak for mentioning the outrageous package. I didn’t know about it. And had I known about it, latex-lookalike may not have needed to come into existance :blush:

Edit 3: @riderpolo instead of using title: none for the outline, and using #text(size: 16pt, weight: "bold")[Inhaltsverzeichnis], you can simply set the language to German had have Typst figure out how to use “Inhaltsverzeichnis” as title for the outline.

#set text(lang: "de")

#outline()

= foo

// etc, ...
1 Like

Technically none is semantically more correct, and it’s slightly more efficient and performant, as it will insert only h(1fr) instead of [ ] + box(width: 1fr)[] + [ ].

Outline Function – Typst Documentation :

Can be set to none to disable filling.

1 Like