How to style headings like text?

I want to style a heading in my document as “regular text”, but it seems the size (or boldness?) of the text persist. Why is that, and how do I achieve a show rule that does display the heading as normal text?

MWE:

#show heading: it => "Lorem Ipsum"

= Title
Title

Result:
image

What causes the “Lorem Ipsum” to remain bold / big? I expected it to be exactly like the “title” behind it.

Hello @xbmbmx and welcome! I have renamed your topic to “How to style headings like text?”, don’t hesitate to read How to post in the Questions category, as


As for your question, the show rule on heading still returns a heading element, which is styled bold by default and has a bigger font size.

It is indeed confusing at first, because you would expect the show rule function format to “replace” the element. From the docs

For maximum flexibility, you can instead write a show rule that defines how to format an element from scratch

Note that it is written “defines how to format an element” instead of “replaces the element with the function output”.

You can understand it as doing the following:

#show heading: it => "Lorem Ipsum"

= Title
#heading[Title]
#heading(depth: 1, body: [Title])
#heading(depth: 1, body: "Lorem Ipsum")

Finally, you can make it look like text if you set it like this

#show heading: set text(11pt, weight: "regular")

I don’t think that’s quite right: this show rule really replaces the heading with simple text. This is why in the following example the first show rule has no effect:

#show heading: it => [x] + it
#show heading: it => "Lorem Ipsum"

= A

The heading is still in the document (you can still query it and it will still show in the outline) but in the process of showing the heading it is really replaced with text.

I think the reason why you still get the heading styling is that all the show-set rules on heading are active while the body of the show rule is executed, including the default rule which makes the heading larger and bold.

Ah! I have to admit I’m not very familiar with Typst internals. I thought the show rules occured inside the element itself, but did not “replace it”, you just modify the output layout.

that’s the reason why I didn’t think it made sense for the element to be fully replaced by a show rule. The default show-set rules for the heading text are applied to the body of heading. For all practical purposes, if heading disappears during show heading: it => "Lorem", and only the text remains, there would be no reason for the heading show-set rules to apply. My conclusion was that the heading element remained in some form.

Maybe the mistake is to see show-set rules as set rules on the shown element, instead of set rules for the scope in which the element is processed.

For example #show heading: set text(red) is not setting any property of heading but it changes the default color of all text elements in the scope of heading elements. And #show heading: set block(spacing: ...) affects not only the spacing around the heading, but also the spacing around blocks that might be inside of the heading.

There is the edge case of rules like #show heading.where(level: 2): set heading(numbering: none) which indeed set a property of heading. But it’s consistent with the above description: when a heading is processed, all the relevant show-set rules are applied, then the heading is materialized (using these rules) and passed as it value to the show heading: it => ... rules. And these show-it rules still execute in the scope of the show-set rules.

As I understand that’s also true, since the heading still shows up in queries. There’s a subtlety of being in the document without being in the visible output, but I don’t know how it really works.

That seems indeed to be the case. Do you know how I could avoid or disable this behaviour? Ideally I want to make my title output like text. The reason I wanted to use an approach like I did is that I hoped it would truly be replaced with text, so if I later on decide to change the text style for the whole document, I wouldn’t have to manually correct it for the titles (which visually also look like text).

I find it somewhat confusing that my posted show rule doesn’t really “replace” the Heading element with just plain text without any other heading-related styling.

You want to revoke the default show rule. It’s not supported yet but it’s on the roadmap. See also How can I bypass set/show rules to revert to the default? and the linked GitHub issue.

In the meantime you can apply a show rule that manually undoes the default rules:

#show heading.where(level: 1): set text(1em/1.4)
#show heading.where(level: 2): set text(1em/1.2)
#show heading: set text(weight: "regular")

It’s not very elegant but I think putting that at the top of your document should work fine (i.e. if you change the text style for the whole document, it should also affect the headings as expected).