Working with tables
add/del mark content — a word, a cell, a whole figure — but a table’s own shape is different: Typst’s table() has no built-in way to conditionally include or exclude an entire row or column depending on the compile mode. Getting this wrong doesn’t just look off — it can leave a row that reviewers were told was added missing from the manuscript actually submitted, or a removed row still sitting in it.
Adding a row or column
An added row or column stays in the table in both compiles, exactly like any other #add[...] — accepted new content never disappears from the clean version. No mode() check at all: wrap each cell in add[...] and include the row unconditionally, same as writing any other table row by hand.
#import "../../lib.typ": *
#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#passage[
#figure(
table(
columns: 2,
[Group], [N],
[Control], [42],
add[Treatment], add[45],
),
caption: [Sample sizes by group.],
)
]
Clean:
Tracked:
Removing a row or column
The opposite: a genuinely removed row or column must be absent from the clean compile, and there’s no native way to hide part of a table conditionally. The fix is to build that row’s cells as a spread array that’s empty in clean and populated in tracked — ..if mode() == "clean" { () } else { (del[...], ...) } — the same mode() already used above for require-exchange-free examples, exported by lib.typ for exactly this.
#import "../../lib.typ": *
#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#passage[
#figure(
table(
columns: 2,
[Group], [N],
[Control], [42],
..if mode() == "clean" { () } else { (del[Treatment], del[45]) },
[Placebo], [40],
),
caption: [Sample sizes by group.],
)
]
Clean:
Tracked:
Combining both in one table
A table can have an added row and a removed row at the same time — the two patterns above coexist without conflict, since neither changes columns:.
#import "../../lib.typ": *
#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
#passage[
#figure(
table(
columns: 2,
[Group], [N],
[Control], [42],
..if mode() == "clean" { () } else { (del[Placebo], del[40]) },
add[Treatment], add[45],
),
caption: [Sample sizes by group --- Placebo dropped, Treatment added.],
)
]
Clean:
Tracked:
Columns are the trap
columns: is one fixed count for the whole table, so an added column and a removed column do not belong in the same delta: an added column is part of the fixed base count (present in both compiles, like the row case above), and only a removed column belongs in a mode-dependent addition to that count — base + int(mode() != "clean") per removed column, never per added one. Writing it the other way around silently drops the added column from the clean, submitted manuscript — easy to miss, since manuscript-tracked.pdf still looks right.#import "../../lib.typ": *
#set page(width: 16.6cm, height: auto, margin: 12pt)
#set text(size: 10.5pt)
// Only the removed column enters the mode-dependent delta --- the
// added column is part of the fixed base count, present in both
// compiles, same as the added row above.
#passage[
#figure(
table(
columns: 3 + int(mode() != "clean"),
[Group], [N], add[p-value], ..if mode() == "clean" { () } else { (del[Old score],) },
[Control], [42], add[0.03], ..if mode() == "clean" { () } else { (del[--],) },
),
caption: [Sample sizes --- p-value column added, Old score column dropped.],
)
]
Clean:
Tracked:
| ← change-list | Bibliography → |