I wanted to write a longish table with groups of rows (separated by hlines) that should be kept together when the table flows over to the next page. The trick with an empty block and a negative v() space didn’t work well as it needs to know the resulting height of the row group beforehand which is hard to get at (with context and measure()).
Eventually I found a simpler solution that worked for me. I’d like to share it – not only for the benefit of anyone who might need it but also in the hope for improvement if there are better and/or easier ways to achieve the same effect.
So here is a short demo:
#let data = ("a", "b", "c", "d", "e", "f", "g", "h", "i",)
// regular table, will have pagebreaks somewhere
#table(
columns: 2,
stroke: none,
table.header([*left*], [*right*]),
..for d in data {
(
table.hline(),
[This is a left entry for #d;.],
[This is a right entry for #d;.],
[A second left entry], [A second right entry],
[A third left entry], [A third right entry],
[A fourth left entry], [A fourth right entry],
[A fifth left entry], [A fifth right entry],
)
},
table.hline(),
)
// the following table will be broken only at the `hline` block boundaries
#table(
columns: (auto, auto, 0mm),
column-gutter: (0pt, 0pt), // with non-zero gutter, leave last one at 0pt!
stroke: none,
table.header([*left*], [*right*]), // no header for the dummy column
..for d in data {
(
table.hline(),
[This is a left entry for #d;.],
[This is a right entry for #d;.],
table.cell(rowspan: 5, breakable: false, ""), // ← insert this per block
[A second left entry], [A second right entry],
[A third left entry], [A third right entry],
[A fourth left entry], [A fourth right entry],
[A fifth left entry], [A fifth right entry],
)
},
table.hline(),
)
The number of lines in each block has to be known and inserted into the rowspan. For generated content this shouldn’t be hard; for hand-written content it’s unwieldy, though.