Overflow and fitting
A cell does not resize its content. A body larger than its cell is drawn past the edge, so a slide that holds too much fails silently on screen rather than at compile time. Before presenting, run a checking compile to find those slides, and scale the rare indivisible block with m.fit.
Inspecting overflowing cells
Overflow observation is off by default, because measuring every cell on every frame roughly doubles the layout work a deck does. It is a checking pass, not something to leave on while you write. The usual way to run it is to set overflow: "error" on setup and compile once before presenting: Mosaic renders the whole deck, then fails naming every overflowing cell with its slide and frame.
For tooling that would rather read the records than stop the build, setup(overflow: "record") emits them and keeps compiling:
'query(<mosaic-overflow-warning>).map(it => it.value)' \
--in slides.typ
Each record identifies the slide, frame, cell, and measured height. Typst gives a package no warning channel, so "record" prints nothing on its own; see the Setup API.
An overflow means the slide holds more than it can show. The remedy is editorial: cut a bullet, split the slide in two, or move to a layout with more room. Mosaic deliberately offers no automatic shrink-to-fit for body content, because a deck whose type size is decided slide by slide loses the scale that holds it together.
Fitting a block to its cell
When a single indivisible block is the problem, a wide table, a chart, or a generated list, scale that one block with m.fit and leave the deck’s typography alone:
#m.slide[
== Regression results
#m.fit(my-table)
]It measures the block against the space its cell gives it, scales it geometrically, and reflows the surrounding layout around the new size. Shrinking is the default, and it takes no hand-picked factor, so the block stays within the cell when the table gains a row. grow: true also scales content up, which is how a single number or word fills a cell.
The block is offered the cell’s width first, so text and lists wrap and are then scaled only if they are still too tall. A table or diagram given a narrower width rearranges itself instead of shrinking, so wrap: false measures and scales it as written.
width: and height: fit to part of the region instead of all of it, and take a length, ratio, or fraction. A fitted block cannot overflow, so it no longer appears in the overflow records.
Measuring a block means holding it inside a closure, which the slide runtime cannot look into. m.pause, m.steps, and m.note are found by walking the slide’s content, so inside a fitted block they would be invisible: the reveals would collapse into one frame and the notes would never reach the speaker output. m.fit reports that as an error instead. Keep them outside the fitted block, or fit each revealed part on its own.
#import "@preview/mosaic:0.0.1" as m
#show: m.setup
#set text(size: 22pt)
#let estimates = table(
columns: 8,
align: (left, right, right, right, right, right, right, right),
inset: 0.6em,
table.header(
[Specification], [Estimate], [Std. error], [$t$], [$p$],
[CI lower], [CI upper], [Observations],
),
[Baseline], [0.412], [0.081], [5.09], [$<$0.001], [0.253], [0.571], [12,480],
[With covariates], [0.386], [0.079], [4.89], [$<$0.001], [0.231], [0.541], [12,480],
[Region fixed effects], [0.344], [0.092], [3.74], [$<$0.001], [0.164], [0.524], [12,480],
[Region and year effects], [0.351], [0.095], [3.69], [$<$0.001], [0.165], [0.537], [12,480],
)
// The table is wider than the cell. `wrap: false` keeps its columns as written
// and scales the whole block, instead of letting the table re-lay out narrower.
#m.slide[
== Regression results
#m.fit(wrap: false, estimates)
]
// The other direction: display type scaled up until it fills the cell.
#m.slide[
== Response rate
#m.fit(grow: true)[42%]
]
See the Slides API for the full m.fit signature.