How can I format the first row of a table using a single show rule?

Hello!
I want to apply the following formatting rules to the table: the cells in the first row should have a gray background, and the text in all the cells of the first row should be bold. At the same time, I do not want to split the display rules into separate blocks, as in the following example:

#set table(
  fill: (_,y) => {
    if y == 0 {
      gray
    } else {
      white
    }
  }
)

#show table.cell.where(y: 0): it => {
  strong(it)
}

#table(
    columns: (auto,auto,auto),
    [354],[546],[564],
    [231],[235],[345],
    [876],[476],[275],
)

I would like to fit all the display rules into a single #show block. I wrote the following code:


#show table.cell.where(y: 0): it => {
  table.cell(
    fill: gray,
    strong(it)
  )
  
}

#table(
    columns: (auto,auto,auto),
    [354],[546],[564],
    [231],[235],[345],
    [876],[476],[275],
)

The online Typst editor did not detect any errors, but the cells in the first row did not turn gray:

please help me solve this problem.

Hi. I see that you’ve created (basically) a duplicate of How to fill the first row of a table with a color?. There is no need to do that, you can just continue the conversation there. Although, at this point, might as well continue here. :)

Currently, some show/set rules for table stuff do not work, I think show: table.cell: set table.cell is one of them (show heading: set heading, for example, works). But regardless of that, You should always prefer the use of set rules or show-set rules over a show rule with a closure, because the latter creates a wrapper over the selected element (table.cell in this example), which make it harder or impossible to modify the styling later. If set or show-set (or set-if) rules are not powerful enough for your use case, then of course you should use show rule to override the way an element is displayed.

In How to fill the first row of a table with a color? - #2 by quachpas you can actually use 1 set rule and 1 show-set rule instead:

#set table(fill: (_, y) => if y == 0 { gray })
#show table.cell.where(y: 0): set text(weight: "bold")

#table(
  columns: 3,  // equivalent to (auto, auto, auto)
  [123], [1123], [1176],
  [657], [5643], [4567],
  [4567], [8970], [234],
)

Note that sometimes you might prefer strong over set text(weight: "bold"), but it’s very nuanced, and depends on the use case.

This way you can later undo those settings by writing

#set table(fill: none)
#show table.cell.where(y: 0): set text(weight: "regular")

Currently, there is no support for revoking rules yet, but if you just want to use the styling for a single table, then you can either use it directly when creating a table, or wrap it all in a new scope:

#{
  set table(fill: (_, y) => if y == 0 { gray })
  show table.cell.where(y: 0): set text(weight: "bold")

  table(
    columns: 3, // equivalent to (auto, auto, auto)
    [123], [1123], [1176],
    [657], [5643], [4567],
    [4567], [8970], [234],
  )
}

Again, overusing show rules is generally discouraged, but now one will stop you from using it. It just can make the setup look less readable, less flexible and introduce some issues down the road. But if it works, it works.

I should also point out that if your table has a header (and not just raw data), then it is advised to use table.header (e.g., table.header[name][name][name]) to provide better accessibility support as well as ability to use show table.header: strong, both in the future,

P.S. If you find an answer to your question in any of the previous or future posts, please mark that specific message (with an answer) as the answer. It helps others quickly find what they are looking for.

2 Likes

Do you have a practical reason for it? If it’s just for aesthetic preferences, consider that you’ll probably have a better time using Typst if you embrace its design rather than try to work around it :slight_smile: And Typst’s design is such that the “right” way do do something is often many small rules rather than a big one.

That said, you can put several rules in a single “show everything” rule:

#show: it => {
  set table(fill: (_, y) => if y == 0 { gray })
  show table.cell.where(y: 0): set text(weight: "bold")
  it
}

(In other words, make a template function.)

Hi @Gasap, I renamed the topic so that it is a question you might ask a friend. See below for more details about recommendations for posting:

1 Like