How can I make '#set block' work for custom blocks only (not for e.g. headings, figures)?

When I use #set block(...) to style custom blocks (#block([...])), it also affects headings and probably some other elements. How to make #set block(...) work for custom blocks only?

#set block(fill: luma(230), inset: 1em, radius: 0.5em, width: 100%)

= Lorem ipsum.

Lorem ipsum dolor sit amet.

#block([
  Lorem ipsum dolor sit amet.
])

Lorem ipsum dolor sit amet.

Let me first share a couple of tips for the given example:

#set block(fill: luma(230), inset: 1em, radius: 0.5em, width: 100%)

= #lorem(2)

#lorem(5)

#block[
  #lorem(5)
]

#lorem(5)

You can use lorem function to make your dummy document code smaller without changing the output. You also don’t have to wrap [] in () when calling some function/element constructor. It’s enough to just use [] instead of (). block() will call the block element constructor without any parameters/arguments, but block[] will pass 1 argument of type content. This can work with all functions that expect at least 1 positional argument. You can also combine both like #text(red)[red text]. Also, a small tip: if you see function1[#something], this means you can simply do function1(something) (i.e., #block(lorem(5))), which is slightly simpler.


Now, the problem with using a global #set block() rule is that most elements in Typst are block-level, which means they internally use block element, and therefore using a global set rule for block will affect many elements. If you need to change block parameters for specific elements, you can use a show-set rule, e.g., #show figure: set block().

Since it looks like you just want to set block parameter for direct block calls, you have 2 general options:

// Option 1
#[
  #set block(fill: luma(230), inset: 1em, radius: 0.5em, width: 100%)
  #block(lorem(5))
]

// Option 2
#block(fill: luma(230), inset: 1em, radius: 0.5em, width: 100%)[
  #lorem(5)
]

image

1 Like

A few other options that might be nicer to use, besides what @Andrew already mentioned:

  • Redefine block (this will then mean, you need some way to access the original block type):
#let std-block = block
#let block = block.with(fill: luma(230), inset: 1em, radius: 0.5em, width: 100%)
  • Use rect instead of block with the exact same arguments.
  • Define a general function instead which doesn’t overwrite block by just calling it #gray-block, for example.
2 Likes

Speaking of std-block, in the upcoming version there is #std.block (or something similar, I’m not sure).

1 Like

You mean this, correct?

#let gray-block = block.with(fill: luma(230), inset: 1em, radius: 0.5em, width: 100%)

= Lorem ipsum.

Lorem ipsum dolor sit amet.

#gray-block[
  Lorem ipsum dolor sit amet.
]

Lorem ipsum dolor sit amet.
2 Likes

To illustrate what you have said, so that it will be even more easier to understand for other novice users like me:

// all the three versions works the same

#quote[
  Lorem ipsum dolor sit amet.
]

#quote([
  Lorem ipsum dolor sit amet.
])

#quote()[
  Lorem ipsum dolor sit amet.
]
1 Like

Typst 0.12 has been released, but it seems std.block doesn’t solve the issue, right?

#set std.block(fill: luma(230), inset: 1em, radius: 0.5em, width: 100%)

= Lorem ipsum.

Lorem ipsum dolor sit amet.

#block([
  Lorem ipsum dolor sit amet.
])

Lorem ipsum dolor sit amet.

That doesn’t work because std.block and block refer to the same thing. If you look back at the proposed solution:

Here you end up with two separate functions std-block and block. This could now be rewritten as

#let block = std.block.with(fill: luma(230), inset: 1em, radius: 0.5em, width: 100%)

Now block and std.block are still different things (as long as block is in scope – i.e. usually in the same file or function) and it will “work”, at least as a workaround to the fundamental issues that Andrew mentioned.

1 Like