How can I remove the numbering from some outline entries?

I am writing a documentation and I have specific requirements regarding the numbering.

In the beginning, I have headings, which must not have a number, therefore I created a tag <unnumbered> and this code:

  show heading.where(label: <unnumbered>): it => {
    // Disable numbering for this heading
    set heading(numbering: none)
    block(
      inset: (left: 0pt),
      it.body,
    )
    // Decrease the heading counter after this unnumbered heading to prevent increment
    counter(heading).update(n => n - 1)
  }

I appended the label <unnumbered> to the heading “Abstract”, “Management Summary”, “Problem Statement” and “Part I - Technical Report”.

Now my outline looks like this:

This is the way I want it, generally. The numbering starts on the chapter “Introduction”

But:
I want to hide the numbers of all of the outline entries that have the label <unnumbered> because they also don’t show a number in the document.
How do I do that?

I thought I could do it with something like this, but it didn’t work:
#show outline.entry.where(label: <unnumbered>): // some code to remove numbers in outline

you could do something like this:

#show outline.entry: it => {
  let no-nums = query(label("unnumbered"))
  if it.element in no-nums {
    // style this as you wish
    return [#it.body() #box(width: 1fr, repeat(gap: 0.15em)[.]) #it.page() \ ]
  }
  it
}

Wow, this was quick! Thank you so much, it worked :smiley:

Just because I’m curious: Do you know why an approach like this doesn’t work:

#show outline.entry.where(label: <unnumbered>):

It seems like it’s not even able to select the outline entries with that label…

No problem! The reason why #show outline.entry.where(label: <unnumbered>): {...} doesn’t work is because where filters for elements belonging to this function whose fields have the values of the given arguments. As a label is it’s own type (i.e., you can’t do #heading("my heading", label: <unnumbered>)), the show rule would not apply to any elements

Hi @ma77hiaz, welcome to our forum! I have edited the title of your question to follow our guidelines.

I guess the headings themselves should have no numbering, I mean not only in the outline but also in the main text? For this you can make the headings by writing

#heading(numbering:none, level: 1)[My Heading]

or if you prefer to use the markup syntax (=) for making the heading: you can do it in a #[...] scope with different settings than other headings:

#[
  #set heading(numbering: none)
  = My Heading
]
1 Like

I’d rather say the problem is that the label is a field of the heading element, not the outline.entry element. For example to automatically remove the numbering from headings that have the label <unnumbered> (and that received a numbering from another set rule) you can do

#show heading.where(label: <unnumbered>): set heading(numbering: none)

and in your solution, you can simplify the code a bit by accessing this label field:

#show outline.entry: it => {
  if it.element.at("label", default: none) == <unnumbered> {
    // style this as you wish
    return [#it.body() #box(width: 1fr, repeat(gap: 0.15em)[.]) #it.page() \ ]
  }
  it
}

Something that indeed doesn’t work is to try setting the numbering in a show-it rule:

#show heading.where(label: <unnumbered>): it => {
  set heading(numbering: none)
  it
}

Here’s it’s too late to change it like that since the it element is already materialized.

1 Like

And to add to @sijo’s answer you can also just set a numbering after all the unnumbered parts of the document.

#outline()

= Unnumbered Heading

#set heading(numbering: "1.1")

= Numbered Heading

IMO the solution with labels seem a bit overengineered/unnecessarily complicated.

2 Likes

Thank you guys for all the explanation and suggestions, really appreciate it!

@sijo , that’s an elegant solution, thanks!

@flokl , I actually do need to have it the complicated way, because throughout the document I do have outline entries that need to be unnumbered. It’s basically “Sections” of the document which can’t have a number.

As a final addendum to this pretty spot on analysis: It would be better to wrap the entry’s contents in a block rather than using a linebreak. That’s how the outline itself does it and it (a) keeps block spacing rules working, (b) means the entry is correctly identified as not a paragraph.

Also it.inner() can be used to get ready-made contents with the body, filler, and page.

So the total thing would be block(it.inner()).

1 Like

Wow, I’m blown away by the activity and the quality of the answers in this forum!

So to summarize everything, the correct solution will look like this:

#show outline.entry: it => {
  if it.element.at("label", default: none) == <unnumbered> {
    return block(it.inner())
  }
  it
}
2 Likes