How to make each grid cell take up all available space?

Sorry, I can’t find a proper and concise way to describe the problem in the title. Let me explain in detail here.

I’m making a poster with many color boxes. I want all boxes aligned and fill up all available vertical space and thus there is no extra blank areas. Here is a simplified version of it:

#set page(width: 300pt, height: 200pt)

#set rect(
  inset: 8pt,
  fill: rgb("e4e5ea"),
  width: 100%,
  radius: 5pt,
)

#grid(
  columns: (1fr, 1fr, 1fr),
  gutter: 3pt,
  grid.cell(rowspan: 2, rect[
    I don't want to use `fill` provided by `grid` because I can not get nice `radius`.\
    This is 2 rows.
  ]),
  rect[How to make this expand?],
  rect[I want each cell to take up all available space.],
  rect[I don't want to hard code heights of each row.],
  rect[How to make this expand?],
)

The result:
Current result
The desired layout should look like the following:
Desired layout
It is achieved by using fill provided by grid, but I don’t want to use it because it is much less flexible than rect or other things. For example, it cannot have radius set. Is it possible to make all rect automatically take up all vertical spaces?

Hello @AllanChain,

the Fraction type can be used to fill the remaining space in a layout. You can set the height of the rect boxes with #set rect(height: 1fr) to take all the remaining space. Now you also have to limit the height of the grid with rows: 1fr otherwise the rect boxes span the entire page.

Code
#set page(width: 300pt, height: 200pt)

#set rect(
  height: 1fr,
  inset: 8pt,
  fill: rgb("e4e5ea"),
  width: 100%,
  radius: 5pt,
)

#grid(
  columns: (1fr, 1fr, 1fr),
  rows: 1fr,
  gutter: 3pt,
  grid.cell(rowspan: 2, rect[
    I don't want to use `fill` provided by `grid` because I can not get nice `radius`.\
    This is 2 rows.
  ]),
  rect[How to make this expand?],
  rect[I want each cell to take up all available space.],
  rect[I don't want to hard code heights of each row.],
  rect[How to make this expand?],
)

test

1 Like

Note that this only works from 0.12.0 onwards, which is still in its testing phase, as rect doesn’t accept fraction type in its height in previous versions.

In 0.11.1 you can add #v(1fr) at the end of each rect to achieve the same effect:

#set page(width: 300pt, height: 200pt)

#set rect(
  inset: 8pt,
  fill: rgb("e4e5ea"),
  width: 100%,
  radius: 5pt,
)

#show grid.cell: it => {
  rect(it+v(1fr))
}

#grid(
  columns: (1fr, 1fr, 1fr),
  rows: 1fr,
  gutter: 3pt,
  grid.cell(rowspan: 2, [
    I don't want to use `fill` provided by `grid` because I can not get nice `radius`.\
    This is 2 rows.
  ]),
  [How to make this expand?],
  [I want each cell to take up all available space.],
  [I don't want to hard code heights of each row.],
  [How to make this expand?],
)
2 Likes

First things first, it’s worth mentioning that the “happy path” for grid fill is to use the built-in fill parameter for grid and grid cells, since that fill is handled by the grid itself and always covers the whole cell.

With that not being possible here due to the desired radius, the ideal solution would be to remain with auto-sized rows (the default), but set rect(height: 100%) on each rectangle so that each rectangle occupies the final measured height for the cell. However, by default, 100% in an auto row always means 100% of the page’s (or parent container’s, if there is one) height, instead of the row height, to avoid a cyclic dependency problem (the auto row height depends on the cells’ heights, but the cells’ heights would depend on the auto row height); you cannot currently change that, but there is a proposal to be able to do so (which would alleviate the need for extra measure() calls): Add `table.cell(fit: Axes<bool>)` parameter · Issue #4000 · typst/typst · GitHub

For the time being, setting the row height to 1fr as suggested above does work to some extent, in that all remaining space will be equally divided between each row of rectangles, but more importantly, sets 100% to mean the row height, allowing you to #set rect(height: 100%), leading to the desired effect. (100% is equal to the row height for all row sizes except for auto.) However, this has the problem that 1fr will be relative to your whole page, so I’d recommend using fixed height rows for this purpose. Regardless of the approach taken, setting the rectangle heights to 100% (or to some fixed size if you prefer) is the preferred solution (and does not require using Typst 0.12.0):

#set page(width: 300pt, height: 400pt)

#set rect(
  inset: 8pt,
  fill: rgb("e4e5ea"),
  width: 100%,
  height: 100%,  // <--- /!\
  radius: 5pt,
)

#grid(
  columns: (1fr, 1fr, 1fr),
  gutter: 3pt,
  rows: 1fr,
  // rows: (8em, 6em), // <--- would be ideal
  grid.cell(rowspan: 2, rect[
    I don't want to use `fill` provided by `grid` because I can not get nice `radius`.\
    This is 2 rows.
  ]),
  rect[How to make this expand?],
  rect[I want each cell to take up all available space.],
  rect[I don't want to hard code heights of each row.],
  rect[How to make this expand?],
)

output

3 Likes

I’ll add that another awesome idea is to open an issue in our GitHub proposing a radius parameter for grid cells’ fill: Issues · typst/typst · GitHub

Thanks for elaborating. Now, I understand that it is currently very difficult to have auto-sized rows while having a growable rect content in Typst.

The rows: 1fr suggested here and above does work in my example, but does not work nicely in my real world poster because all rows are evenly spaced relative to the page. What I really want is auto-sized rows, and I’m sorry that I didn’t make it clear in the question.

Therefore, I’m setting a fixed height and use height: 100% for now. I will follow up the issue you mentioned.

Glad you managed to solve it! Let’s mark my answer as a solution for now then, and we can maybe change that in the future when that issue is closed. :slight_smile:

I can’t find the “mark as solution” button now, but I’m sure it existed days before. Is the forum site updated? Also, I’m unable to login on other devices (Unable to log in to the forum), which is strange.

Yeah, it appears there is an ongoing issue with the forum, sorry for that. Hopefully it should be solved soon.