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
]

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.

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.

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()).

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
}

If you don’t want it to show up in the toc (table of contents), you can also set outlined to false:

#[
  #set heading(numbering: none, outlined: false)
  = My Heading
]