How to style multi-level headers in a table? Basically I want to know is there a way we can globally define styles for header

I am adding styles to the tables like this because, I have large number of tables in my report.
Also I have tables with I have 0, 1 header , 2 and 3 headers row.

#show table.cell.where(y: 0): set text(fill: white, weight: "bold")

Also this is the typst code for one of my two row header table , as you ca see I can only see level one header styled


#table(
  columns: (0.5fr, 2fr, 1fr, 1fr, 1fr, 1fr, 1fr), // Added a column for "Other"
  inset: 8pt,
  align: horizon,
  stroke: 0.5pt,
  table.header(
    table.cell(rowspan: 2, text(hyphenate: auto)[*S. \ No.*]),
    table.cell(rowspan: 2, [*Particulars*]),
    table.cell(rowspan: 2, [*Total (A)*]),
    table.cell(colspan: 2, [*Male*]),
    table.cell(colspan: 2, [*Female*]),
    [*No. (B) *],[*% (B / A) *],[*No. (C) *],[*% (C / A)*]
  ),
  table.cell(colspan: 7, align(center)[#underline[*EMPLOYEES*]]),
  "1.","Permanent (D)", "[Data]", "[Data]", "[Data]", "[Data]","[Data]",
  "2.","Other than Permanent (E)", "[Data]", "[Data]", "[Data]", "[Data]","[Data]",
  "3.",[*Total employees (D + E)*], "[Data]", "[Data]", "[Data]", "[Data]","[Data]",
    table.cell(colspan: 7, align(center)[#underline[*WORKERS*]]),
  "1.","Permanent (F)", "[Data]", "[Data]", "[Data]", "[Data]","[Data]",
  "2.","Other than Permanent (G)", "[Data]", "[Data]", "[Data]", "[Data]","[Data]",
  "3.",[*Total workers (F + G)*], "[Data]", "[Data]", "[Data]", "[Data]","[Data]",
)

Basically I want to know is there a way we can globally define styles for header .

Hi, something that works well for your table is a parameter to the table like this:

fill: (x, y) => if y <= 1 { navy.lighten(50%) },

This adds a background color to y <= 1 which is row 1 and 2, since you have a 2-row header, this is correct.

The white/bold rule you similarly have to duplicate for y: 0 and y: 1.

I don’t think there is a great solution for figuring out how many rows of header each table has. I’d style the tables separately, with a helper function.


This is probably how I would set it up - but maybe there will be other suggestions

#let style-header(nrows, ..text-style) = doc => {
  show table.cell: it => {
    set text(..text-style) if it.at("y", default: 999) < nrows
    it
  }
  doc
}


#show <tabheader1>: style-header(1, white, weight: "bold")
#show <tabheader2>: style-header(2, white, weight: "bold")
#show <tabheader3>: style-header(3, white, weight: "bold")
#show <tabheader1>: set table(fill: (x, y) => if y <= 0 { navy.lighten(30%) })
#show <tabheader2>: set table(fill: (x, y) => if y <= 1 { navy.lighten(30%) })
#show <tabheader3>: set table(fill: (x, y) => if y <= 2 { navy.lighten(30%) })

Once these styles are defined, you need to administer them to the correct tables. You’d either label each table with the relevant label or wrap each table in a function that applies the correct style.

(This comes out of some experimentation - we can try to write a function to check how many rows of headers a table has but (1) the logic for wrapping cells and computing that correctly for every table is complicated and (2) we can change cell styling but not table fill at that stage.)