How to prevent pagebreak (or ensure stickyness) in certain stream of blocks?

I tried to create a fancy box using the following minimal example. However, when the block break across pages, it sometimes breaks such that the title is not with its child. How I can prevent this?

#set page(height: 3cm, width: 4cm)
#let myblock(title, body) = {
  block({
    move(block(fill: yellow, title, inset: 0.2em,), dx: 0.5em, dy: -0.6em)
    v(-1em)
    body
  }, stroke: 1pt, width: 100%)
}

#myblock[
  Title
][
  #lorem(5)
]

#myblock[Another][
  #lorem(20)
]

The rendered output:

expected:

which was rendered from:

#set page(height: 3cm, width: 4cm)
#let myblock(title, body) = {
  block({
    move(block(fill: yellow, title, inset: 0.2em,), dx: 0.5em, dy: -0.6em)
    v(-1em)
    body
  }, stroke: 1pt, width: 100%)
}

#myblock[
  Title
][
  #lorem(5)
]

#pagebreak() // Here!

#myblock[Another][
  #lorem(20)
]

Hi there @Pakorn , try setting block breakable: false

Whether the block can be broken and continue on the next page.

From Typst Doc: Block Function – Typst Documentation

#let myblock(title, body) = {
  block(
    breakable: false, // <--
    {
    move(block(fill: yellow, title, inset: 0.2em,), dx: 0.5em, dy: -0.6em)
    v(-1em)
    body
  }, stroke: 1pt, width: 100%)
}

That would cause the block not to break at all, which also is not desirable.
As you can see in the expected behavior, the overall block should be able to break across page, just the title that should stick with its body.

Sorry I went a bit fast on that. The MRE and the expected behaviour are not the same… Hence my quick reply as it did solve the problem on the MRE. I understand the requirement now. Would you update your MRE so it matches the desired behaviour please?

No worries, but what is MRE?

Your code snippet in your first post.

A Minimal reproducible example - Wikipedia is a piece of code that contains only the required code to reproduce the issue you are having.

Then, if you also post the expected result, we can work together in order to reach the state where you are satisfied, i.e. the issue is solved.

#lorem(20) instead of “Things” will probably work (that is what I am using now).

I didn’t noticed that, thank you.
Now the code has been updated.

1 Like

I thought sticky: true on the block sticky - Typst Documentation would have solved it but it doesn’t work (or I can’t make it work). Perhaps related to Block loses stickness when containing large text · Issue #6546 · typst/typst · GitHub.

These packages are not solving your problem but worth looking at as they seems to do similar things:

What do you think of this? Setting pagebreak(weak:true) does solve the issue.

#let myblock(title, body) = {
  block({
    move(block(fill: yellow, title, inset: 0.2em,), dx: 0.5em, dy: -0.6em)
    v(-1em)
    body
  }, stroke: 1pt, width: 100%)
  pagebreak(weak:true)  //<--
}

You can wrap your title block with another block which is sticky and sticks to the body.

#let myblock(title, body) = {
  block({
    block(sticky: true, below: 0.2em, move(block(fill: yellow, title, inset: 0.2em), dx: 0.5em, dy: -0.6em))
    body
  }, stroke: 1pt, width: 100%)
}
1 Like

Nice. Out of interest, do you have any idea why sticky: true doesn’t work inside the inner block?

Not really. Maybe because it is inside move?

Since @flokl covers the more cases (e.g. having two blocks in the same page)
So I marked his as solution.
Thank you all.

1 Like