How can I set the alignment of table cells for certain rows and columns through a function?

I’m trying to centre all cells in a table except the ones in the header (first row) and the last column.

When I try the following code, the typst CLI compiler prints out for the second line, error: expected alignment or auto, found none.

#let ktable(..cells) = {
  set table(align: (x, y) => {
    if x in (0, 1, 2) and y > 0 {
      // Align vertically and horizontally
      center + horizon
    }
  })
  show table.cell: c => {
    if c.y > 0 and c.x == 0 {
      return text(22pt, c)
    }
    c
  }
  table(
    stroke: (x: none, y: color.rgb("#DEDEDE")),

    columns: (50pt, 50pt, auto, auto),
    inset: 8pt,

    table.hline(stroke: black),

    table.cell(align: center)[*Char.*],
    table.cell(align: center)[*Keyword*],
    table.cell(align: center)[*Index*],
    table.cell(align: center)[*Story*],
    table.hline(stroke: black),

    ..cells,

    table.hline(stroke: black),
  )
}

#ktable(
  [吾], [I], [11],
  [#lorem(10)],

  [明], [bright], [20],
  [#lorem(10)],

  [唱], [chant], [21],
  [#lorem(10)],
)

In align, you are only returning a value when your conditions are met. You need to return a default value.

Do you mean I need to add something to declare the value as default?

To complement this answer, whenever you write an if without an else, there’s an implicit else { none }:

#repr(if 5 != 5 { "something" })  // none

// this is because the above is equivalent to
#repr(if 5 != 5 { "something" } else { none })  // none

So, the problem arises in this part of your code:

#set table(align: (x, y) => {
    if x in (0, 1, 2) and y > 0 {
      // Align vertically and horizontally
      center + horizon
    } // else { none } is implicit
  })

When the condition doesn’t match, you’re setting an alignment of none, which isn’t valid!

Instead, add an explicit else { auto } (auto is the default and means that alignment should be inherited from outside the table):

#set table(align: (x, y) => {
    if x in (0, 1, 2) and y > 0 {
      // Align vertically and horizontally
      center + horizon
    } else {
      // Use alignment from outside
      // (Alternatively: can use 'start + top' as default)
      auto
    }
  })
2 Likes

Thank you for the detailed explanation!